library:
#install.packages("caret")
#install.packages("glmnet")
#install.packages("Boruta")
#install.packages("mlbench")
#install.packages("randomForest")
library(outliers)
library(dplyr)
library(mlbench)
library(caret)
library(glmnet)
library(Boruta)
library(ggplot2)
library(randomForest)
library(pROC)
library(e1071)
library(caret)
library(party)
library(partykit)
library(RWeka)
library(C50)
library(printr)
library(rpart)
library(rpart.plot)
getwd()
[1] "/Users/mahayie/Documents/GitHub/DM1Project"
#setwd("/Users/mahayie/Desktop/326p")
#getwd()
water_potability = read.csv('Dataset/water_potability.csv')
str(water_potability)
'data.frame': 3276 obs. of 10 variables:
$ ph : num NA 3.72 8.1 8.32 9.09 ...
$ Hardness : num 205 129 224 214 181 ...
$ Solids : num 20791 18630 19910 22018 17979 ...
$ Chloramines : num 7.3 6.64 9.28 8.06 6.55 ...
$ Sulfate : num 369 NA NA 357 310 ...
$ Conductivity : num 564 593 419 363 398 ...
$ Organic_carbon : num 10.4 15.2 16.9 18.4 11.6 ...
$ Trihalomethanes: num 87 56.3 66.4 100.3 32 ...
$ Turbidity : num 2.96 4.5 3.06 4.63 4.08 ...
$ Potability : int 0 0 0 0 0 0 0 0 0 0 ...
sample of data
sample of raw dataset(first 10 rows):
head(water_potability,10)
sample of raw dataset(last 10 rows):
tail(water_potability, 10)
Five number summary of each attribute in our dataset:
summary(water_potability)
ph Hardness Solids Chloramines Sulfate Conductivity
Min. : 0.000 Min. : 47.43 Min. : 320.9 Min. : 0.352 Min. :129.0 Min. :181.5
1st Qu.: 6.093 1st Qu.:176.85 1st Qu.:15666.7 1st Qu.: 6.127 1st Qu.:307.7 1st Qu.:365.7
Median : 7.037 Median :196.97 Median :20927.8 Median : 7.130 Median :333.1 Median :421.9
Mean : 7.081 Mean :196.37 Mean :22014.1 Mean : 7.122 Mean :333.8 Mean :426.2
3rd Qu.: 8.062 3rd Qu.:216.67 3rd Qu.:27332.8 3rd Qu.: 8.115 3rd Qu.:360.0 3rd Qu.:481.8
Max. :14.000 Max. :323.12 Max. :61227.2 Max. :13.127 Max. :481.0 Max. :753.3
NA's :491 NA's :781
Organic_carbon Trihalomethanes Turbidity Potability
Min. : 2.20 Min. : 0.738 Min. :1.450 Min. :0.0000
1st Qu.:12.07 1st Qu.: 55.845 1st Qu.:3.440 1st Qu.:0.0000
Median :14.22 Median : 66.622 Median :3.955 Median :0.0000
Mean :14.28 Mean : 66.396 Mean :3.967 Mean :0.3901
3rd Qu.:16.56 3rd Qu.: 77.337 3rd Qu.:4.500 3rd Qu.:1.0000
Max. :28.30 Max. :124.000 Max. :6.739 Max. :1.0000
NA's :162
Number of column and rows
dim(water_potability)
[1] 3276 10
Sample of Water_potability dataset
This is a sample of the dataset to help to understand how it is
structured and organized
View(water_potability)
sample(water_potability)
Checking for missing values:
The absence of data in certain variables or columns in a dataset is
referred to as missing or null values due to various reasons. It can
have a negative impact on the dataset’s efficiency and the information
that can be taken from it later, so we checked to see whether our data
had missing or null values and eliminated these rows to produce a more
efficient dataset.
first we checked for missing value to ensures accurate statistics,
reliable visualizations, and guides decisions on imputation or removal
of missing data.
dim(water_potability)
[1] 3276 10
sum(is.na(water_potability))
[1] 1434
Remove rows with missing values
colSums(is.na(water_potability))
ph Hardness Solids Chloramines Sulfate Conductivity Organic_carbon
491 0 0 0 781 0 0
Trihalomethanes Turbidity Potability
162 0 0
water_potability = na.omit(water_potability)
colSums(is.na(water_potability))
ph Hardness Solids Chloramines Sulfate Conductivity Organic_carbon
0 0 0 0 0 0 0
Trihalomethanes Turbidity Potability
0 0 0
View(water_potability)
second remove rows
Standard deviation:
The standard deviation in statistics is a measure used to assess the
spread of data around the mean. It gives us an idea of how much the data
points deviate from the average.
sd(water_potability$Turbidity)
[1] 0.7803462
sd(water_potability$Solids)
[1] 8642.24
sd(water_potability$Conductivity)
[1] 80.71257
sd(water_potability$Organic_carbon)
[1] 3.324959
sd(water_potability$ph)
[1] 1.573337
we ues it for five coulme
Turbidity,Solids,Conductivity,Organic_carbon,ph.
Mean:
the average, is a measure of central tendency in statistics. It is
calculated by summing up all the values in a dataset and dividing by the
number of values. The mean gives us a representative value that is
typically used to describe the “typical” value in a set of data.
mean(water_potability$Turbidity)
[1] 3.969729
mean(water_potability$Solids)
[1] 21917.44
mean(water_potability$Conductivity)
[1] 426.5264
mean(water_potability$Organic_carbon)
[1] 14.35771
mean(water_potability$ph)
[1] 7.08599
we ues it for five coulme
Turbidity,Solids,Conductivity,Organic_carbon,ph.
Variance:
It provides information about how far each value in the dataset is
from the mean. A higher variance indicates a greater spread of data,
while a lower variance suggests that the data points are closer to the
mean.
var(water_potability$Turbidity)
[1] 0.6089401
var(water_potability$Solids)
[1] 74688309
var(water_potability$Conductivity)
[1] 6514.519
var(water_potability$Organic_carbon)
[1] 11.05535
var(water_potability$ph)
[1] 2.475388
As you can see the highest Variance Solids, and the lowest
Turbidity.
Statistical Measures:
In the given code, you’ve used the summary function to obtain key
statistical measures for variables such as “Conductivity,”
“Organic_carbon,” “Hardness,” etc., in the water_potability dataset.
These measures include minimum, 1st quartile, median, mean, 3rd
quartile, and maximum values, offering a succinct overview of each
variable’s distribution and characteristics. This provides essential
insights for the initial exploration and
understanding of the dataset.
With using minimum, maximum, mean, median laws it helps to provide an
overview of the data’s key characteristics
summary(water_potability$Conductivity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
201.6 366.7 423.5 426.5 482.4 753.3
summary(water_potability$Organic_carbon)
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.20 12.12 14.32 14.36 16.68 27.01
summary(water_potability$Hardness)
Min. 1st Qu. Median Mean 3rd Qu. Max.
73.49 176.74 197.19 195.97 216.44 317.34
summary(water_potability$Solids)
Min. 1st Qu. Median Mean 3rd Qu. Max.
320.9 15615.7 20933.5 21917.4 27182.6 56488.7
summary(water_potability$Chloramines)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.391 6.139 7.144 7.134 8.110 13.127
summary(water_potability$Potability)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0000 0.0000 0.0000 0.4033 1.0000 1.0000
summary(water_potability$Sulfate)
Min. 1st Qu. Median Mean 3rd Qu. Max.
129.0 307.6 332.2 333.2 359.3 481.0
summary(water_potability$Trihalomethanes)
Min. 1st Qu. Median Mean 3rd Qu. Max.
8.577 55.953 66.542 66.401 77.292 124.000
summary(water_potability$Turbidity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.450 3.443 3.968 3.970 4.514 6.495
summary(water_potability$ph)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.2275 6.0897 7.0273 7.0860 8.0530 14.0000
Data Transformation:
This step involved transforming the class label, Potability, into
categorical data. We changed the numeric data to ‘Not Potable’ and
‘Potable’ to indicate whether the water is safe for human consumption,
where 1 represents ‘Potable’, and 0 represents ’Not Potable.
water_potability$Potability[water_potability$Potability == '0'] <- 'Not Potable'
water_potability$Potability[water_potability$Potability == '1'] <- 'Potable'
water_potability$Potability <- as.factor(water_potability$Potability)
table(water_potability$Potability)
Not Potable Potable
1200 811
print(water_potability)
outliers:
They are observations that lie far away from the majority of the
data. Outliers can occur due to various reasons such as measurement
errors, experimental anomalies, or genuine extreme values.
##before removing outlier:
dim(water_potability)
[1] 2011 10
head(water_potability)
removing outliers:
Removing outliers from a dataset is critical for assuring the quality
and reliability of statistical analysis and machine learning models. We
found all outliers in the numerical attributes and subsequently
eliminated the rows containing the outliers.
- ph
summary(water_potability$ph)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.2275 6.0897 7.0273 7.0860 8.0530 14.0000
quartiles <- quantile(water_potability$ph, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
6.089723 8.052969
iqr <- IQR(water_potability$ph)
iqr
[1] 1.963245
lower <- quartiles[1] - 1.5*iqr
lower
25%
3.144855
upper <- quartiles[2] + 1.5*iqr
upper
75%
10.99784
boxplot(ph ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$ph, ylab = 'ph')$out
out_val
out_rows <- which(water_potability$ph %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}



summary(water_potability$ph)
Min. 1st Qu. Median Mean 3rd Qu. Max.
3.231 6.105 7.027 7.087 8.030 10.905
#-------------------------------------------
-Hardness
summary(water_potability$Hardness)
Min. 1st Qu. Median Mean 3rd Qu. Max.
73.49 176.90 197.36 196.27 216.44 317.34
quartiles <- quantile(water_potability$Hardness, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
176.9031 216.4411
iqr <- IQR(water_potability$Hardness)
iqr
[1] 39.53799
lower <- quartiles[1] - 1.5*iqr
lower
25%
117.5961
upper <- quartiles[2] + 1.5*iqr
upper
75%
275.7481
boxplot(Hardness ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Hardness, ylab = 'Hardness')$out
out_val
out_rows <- which(water_potability$Hardness %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}





summary(water_potability$Hardness)
Min. 1st Qu. Median Mean 3rd Qu. Max.
121.0 177.7 197.3 196.2 215.5 272.1
#-------------------------------------------
-Solids
summary(water_potability$Solids)
Min. 1st Qu. Median Mean 3rd Qu. Max.
320.9 15704.5 20855.3 21840.2 27045.9 56488.7
quartiles <- quantile(water_potability$Solids, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
15704.48 27045.93
iqr <- IQR(water_potability$Solids)
iqr
[1] 11341.45
lower <- quartiles[1] - 1.5*iqr
lower
25%
-1307.69
upper <- quartiles[2] + 1.5*iqr
upper
75%
44058.1
boxplot(Solids ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Solids, ylab = 'Solids')$out
out_val
out_rows <- which(water_potability$Solids %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}



summary(water_potability$Solids)
Min. 1st Qu. Median Mean 3rd Qu. Max.
320.9 15547.5 20518.7 21419.6 26734.7 43195.5
#-------------------------------------------
-Chloramines
summary(water_potability$Chloramines)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.391 6.141 7.135 7.135 8.094 13.127
quartiles <- quantile(water_potability$Chloramines, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
6.141236 8.094323
iqr <- IQR(water_potability$Chloramines)
iqr
[1] 1.953087
lower <- quartiles[1] - 1.5*iqr
lower
25%
3.211605
upper <- quartiles[2] + 1.5*iqr
upper
75%
11.02395
boxplot(Chloramines ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Chloramines, ylab = 'Chloramines')$out
out_val
out_rows <- which(water_potability$Chloramines %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}





summary(water_potability$Chloramines)
Min. 1st Qu. Median Mean 3rd Qu. Max.
3.352 6.181 7.137 7.136 8.076 10.897
#-------------------------------------------
-Sulfate
summary(water_potability$Sulfate)
Min. 1st Qu. Median Mean 3rd Qu. Max.
187.2 308.2 332.6 333.4 358.3 481.0
quartiles <- quantile(water_potability$Sulfate, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
308.1884 358.3020
iqr <- IQR(water_potability$Sulfate)
iqr
[1] 50.11358
lower <- quartiles[1] - 1.5*iqr
lower
25%
233.0181
upper <- quartiles[2] + 1.5*iqr
upper
75%
433.4724
boxplot(Sulfate ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Sulfate, ylab = 'Sulfate')$out
out_val
out_rows <- which(water_potability$Sulfate %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}



summary(water_potability$Sulfate)
Min. 1st Qu. Median Mean 3rd Qu. Max.
237.5 309.2 332.8 333.6 357.7 429.8
#-------------------------------------------
-Conductivity
summary(water_potability$Conductivity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
201.6 366.6 423.6 426.8 482.6 753.3
quartiles <- quantile(water_potability$Conductivity, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
366.5581 482.5983
iqr <- IQR(water_potability$Conductivity)
iqr
[1] 116.0401
lower <- quartiles[1] - 1.5*iqr
lower
25%
192.4979
upper <- quartiles[2] + 1.5*iqr
upper
75%
656.6585
boxplot(Conductivity ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Conductivity, ylab = 'Conductivity')$out
out_val
out_rows <- which(water_potability$Conductivity %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}


summary(water_potability$Conductivity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
201.6 366.4 423.1 426.0 481.9 652.5
#-------------------------------------------
-Organic_carbon
summary(water_potability$Organic_carbon)
Min. 1st Qu. Median Mean 3rd Qu. Max.
4.372 12.184 14.351 14.417 16.788 27.007
quartiles <- quantile(water_potability$Organic_carbon, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
12.18447 16.78779
iqr <- IQR(water_potability$Organic_carbon)
iqr
[1] 4.603315
lower <- quartiles[1] - 1.5*iqr
lower
25%
5.279502
upper <- quartiles[2] + 1.5*iqr
upper
75%
23.69276
boxplot(Organic_carbon ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Organic_carbon, ylab = 'Organic_carbon')$out
out_val
out_rows <- which(water_potability$Organic_carbon %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}


summary(water_potability$Organic_carbon)
Min. 1st Qu. Median Mean 3rd Qu. Max.
5.512 12.222 14.352 14.426 16.786 23.604
#-------------------------------------------
-Trihalomethanes
summary(water_potability$Trihalomethanes)
Min. 1st Qu. Median Mean 3rd Qu. Max.
8.577 55.865 66.231 66.364 77.418 124.000
quartiles <- quantile(water_potability$Trihalomethanes, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
55.86494 77.41789
iqr <- IQR(water_potability$Trihalomethanes)
iqr
[1] 21.55295
lower <- quartiles[1] - 1.5*iqr
lower
25%
23.53552
upper <- quartiles[2] + 1.5*iqr
upper
75%
109.7473
boxplot(Trihalomethanes ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Trihalomethanes, ylab = 'Trihalomethanes')$out
out_val
out_rows <- which(water_potability$Trihalomethanes %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}



summary(water_potability$Trihalomethanes)
Min. 1st Qu. Median Mean 3rd Qu. Max.
24.53 55.96 66.29 66.42 77.34 108.85
#-------------------------------------------
-Turbidity
summary(water_potability$Turbidity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.450 3.441 3.975 3.973 4.519 6.495
quartiles <- quantile(water_potability$Turbidity, probs = c(.25, .75), na.rm = FALSE)
quartiles
25% 75%
3.440859 4.518751
iqr <- IQR(water_potability$Turbidity)
iqr
[1] 1.077892
lower <- quartiles[1] - 1.5*iqr
lower
25%
1.824021
upper <- quartiles[2] + 1.5*iqr
upper
75%
6.135588
boxplot(Turbidity ~ Potability, data = water_potability)

repeat {
out_val <- boxplot(water_potability$Turbidity, ylab = 'Turbidity')$out
out_val
out_rows <- which(water_potability$Turbidity %in% c(out_val))
out_rows
if(sum(out_rows) > 0) water_potability <- water_potability[-out_rows,]
else {break}
}


summary(water_potability$Turbidity)
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.873 3.443 3.974 3.972 4.512 6.084
After removing outliers:
dim(water_potability)
[1] 1750 10
str(water_potability)
'data.frame': 1750 obs. of 10 variables:
$ ph : num 8.32 9.09 5.58 10.22 8.64 ...
$ Hardness : num 214 181 188 248 203 ...
$ Solids : num 22018 17979 28749 28750 13672 ...
$ Chloramines : num 8.06 6.55 7.54 7.51 4.56 ...
$ Sulfate : num 357 310 327 394 303 ...
$ Conductivity : num 363 398 280 284 475 ...
$ Organic_carbon : num 18.4 11.6 8.4 13.8 12.4 ...
$ Trihalomethanes: num 100.3 32 54.9 84.6 62.8 ...
$ Turbidity : num 4.63 4.08 2.56 2.67 4.4 ...
$ Potability : Factor w/ 2 levels "Not Potable",..: 1 1 1 1 1 1 1 1 1 1 ...
- attr(*, "na.action")= 'omit' Named int [1:1265] 1 2 3 9 12 14 15 17 19 21 ...
..- attr(*, "names")= chr [1:1265] "1" "2" "3" "9" ...
head(water_potability)
Charts:
visual representation of data that help us understand and analyze
information more easily. They can be used to display trends,
comparisons, and relationships between different variables. There are
various types of charts, such as
Histogram
The histogram shows the frequency of ph in the dataset; we noted that
the majority of values fall within the usual range, which is about
between 6 and 8, but it also shows several outliers.
hist(water_potability$ph)

hist(water_potability$Chloramines)

hist(water_potability$Hardness)

hist(water_potability$Solids)

hist(water_potability$Sulfate)

hist(water_potability$Conductivity)

hist(water_potability$Organic_carbon)

hist(water_potability$Trihalomethanes)

hist(water_potability$Turbidity)

Bar Plot
the bar plot represent how ph levels affect water portability in the
dataset it indicates that ph level above 10 is not portibal and humans
cant consume it
tab <- water_potability$Potability %>% table()
txt <- paste0(tab)
bb <- water_potability$ph %>% table() %>% barplot( main='ph',col=c('pink'))

bb <- water_potability$Potability %>% table() %>% barplot( main='Potability',ylab='Frequency',col=c('pink', 'lightblue'))
text(bb, tab/2, labels=txt, cex=1)

Scatter Plot
This scatter demonstrates the correlation and proportionality between
the two qualities, allowing us to establish whether or not turbidity and
pH are connected.
with(water_potability, plot(Trihalomethanes, ph, col = Potability, pch = as.numeric(Potability)))

Remove Redundant Features:
This will find the correlation between the features and represent it
in heat map
correlation_matrix <- cor(water_potability[,1:9])
high_correlation_features <- findCorrelation(correlation_matrix, cutoff = 0.5)
print(high_correlation_features)
integer(0)
heatmap(correlation_matrix)

we remove the correlation between the features and represent it in
heat map
Feature selection:
Rank Features By Importance:
ranking features by importance is a technique used to identify the
most influential variables in a dataset for predicting a target
variable. This process helps in understanding which features have the
most impact on the model’s performance. By ranking features by
importance.
#train random forest model and calculate feature importance
rf = randomForest(x= water_potability[,1:9],y= water_potability[,10])
var_imp <- varImp(rf, scale = FALSE)
#sort the score in decreasing order
var_imp_df <- data.frame(cbind(variable = rownames(var_imp), score = var_imp[,1]))
var_imp_df$score <- as.double(var_imp_df$score)
var_imp_df[order(var_imp_df$score,decreasing = TRUE),]
ggplot(var_imp_df, aes(x=reorder(variable, score), y=score)) +
geom_point() +
geom_segment(aes(x=variable,xend=variable,y=0,yend=score)) +
ylab("IncNodePurity") +
xlab("Variable Name") +
coord_flip()

Recursive Feature elimination:
is a feature selection technique that recursively removes less
important features from a model until the optimal subset is identified.
It involves repeatedly training the model, ranking features based on
their importance, and eliminating the least important ones.
{r, warning=FALSE} # control <- rfeControl(functions=rfFuncs, method="cv",number=10) # rf <- trainControl(method = "cv", number = 10, verboseIter = FALSE) # # run the RFE algorithm # rfe_model <- rfe(x= water_potability[,1:9],y= water_potability[,10], sizes=c(1:9), rfeControl=control) # # summarize the results # print(rfe_model) # # list the chosen features # predictors(rfe_model) # # plot the results # plot(rfe_model, type=c("g", "o")) #
Normlization
Normalization refers to the process of scaling variables to have a
common range. It helps in comparing variables with different scales.
normalize=function(x){return ((x-min(x))/(max(x)))}
wp$Solids=normalize(wp$Solids)
Error: object 'wp' not found
The solids attribute will create critical challenges because of the
vast and diverted values: min is 320.9, and max is 43195.5, so we
normalized the solids between 0 and 1 to make values smaller and more
reasonable.
Discretization:
Discretization is the process of transforming continuous variables
into discrete or categorical variables. It can be useful for analyzing
data with many unique values or simplifying it.
Therefore, we transformed the continuous values of the numeric
attributes into intervals by dividing the values to fall on one of the
possible interval labels by discretization. The values will be
meaningful and simpler to classify or perform other methods to help us
later in our model. So, In Trihalomethanes, we intervals by dividing the
values by 10 to have labels with equal width : [20,30) [30,40) [40,50)
[50,60) [60,70) [70,80) [80,90) [90,100) [100,110).
##Encoding
encoding is the process of converting characters or strings into a
specific encoding format. Since we don’t have a Nominal attribute in our
database we couldn’t implement it.
classfication and clustring In our dataset exploration, we employed
both supervised and unsupervised learning methodologies through
classification and clustering techniques.
For classification, we chose the decision tree algorithm, a recursive
approach constructing a tree structure with leaf nodes signifying final
decisions. The objective was to predict the class label (potability),
with values 0 or 1, based on attributes like pH, Hardness, Solids,
Chloramines, Sulfate, Conductivity, Organic_carbon, Trihalomethanes, and
Turbidity. The dataset underwent division into training and testing sets
for constructing and evaluating the decision tree. Model evaluation
encompassed metrics like accuracy and cost-sensitive measures, gauged
using a confusion matrix. Our toolkit included packages such as ‘party’
and ‘caret,’ incorporating methods like ‘sample’ for data splitting,
‘ctree’ for decision tree construction, ‘predict’ for testing
predictions, and ‘confusionMatrix’ for model evaluation.
In the unsupervised clustering phase, we excluded the class label
attribute “potability” and utilized numeric attributes such as pH,
Hardness, Solids, Chloramines, Sulfate, Conductivity, Organic_carbon,
Trihalomethanes, and Turbidity. Employing the K-means algorithm,
clusters were formed, each represented by a center point, and objects
were assigned to the nearest cluster. For this phase, we made use of
packages such as ‘cluster’ and ‘factoextra,’ incorporating methods like
‘scale()’ for data scaling, ‘Kmeans()’ for cluster creation.
Cluster validation was performed using the ‘silhouette()’ method to
calculate averages for each cluster. In both supervised and unsupervised
techniques, we maintained result consistency by employing the
‘set.seed()’ method with the same random number when experimenting with
different dataset sizes.
#Training technique
In the provided code, we systematically addressed outliers in
multiple columns of our dataset. Beginning with a summary of each
column’s statistics, including quartiles and the interquartile range
(IQR), we established outlier detection limits. A visual assessment was
conducted using boxplots, categorized by relevant variables such as
“Potability.” A loop was implemented to iteratively identify and remove
outliers in each column, ensuring a robust cleansing process. The final
step involved summarizing the columns post-outlier removal, offering
insights into the impact on the distribution of each variable. This
comprehensive approach was applied uniformly to all dataset columns,
promoting consistency in the outlier-handling process.
Gain ratio (C4.5)
a decision tree-based classifier, is utilized for model training and
evaluation. The dataset undergoes cross-validation with different fold
settings (3 folds, 5 folds, and 10 folds). For each fold configuration,
a J48 model is trained, and its predictive performance is assessed using
Receiver Operating Characteristic (ROC) curves. The Area Under the Curve
is calculated for each ROC curve, providing a quantitative measure of
the model’s ability to predict water potability. Notably, the visual
inspection of the ROC curves indicates that the model trained with
10-fold cross-validation exhibits the highest discriminative
performance. This comparative analysis across various cross-validation
scenarios offers valuable insights into the robustness and
generalization capability.
C5.0 newer version of C4.5 Splitting the data set into two subsets:
Training(70%) and Testing(30%):
Splitting the data set into two subsets: Training(80%) and
Testing(20%):
Splitting the data set into two subsets: Training(90%) and
Testing(10%):
###To improve the readability of the decision tree, we decided to
sample the data using only the pH and sulfate attributes. We then split
the data into training and testing sets using the same split points:
###Training(90%) and Testing(10%), which allowed for a more manageable
decision tree:
###Gini index (CART) we employed the C5.0 algorithm, an enhanced
version of the C4.5 decision tree, for model training and evaluation
across different training and testing set splits. The dataset underwent
three scenarios: Training(70%) and Testing(30%), Training(80%) and
Testing(20%), and Training(90%) and Testing(10%). For each case, the
C5.0 model was trained on the designated training data, evaluated on the
testing data, and its performance was assessed through accuracy,
confusion matrix, and ROC curve with Area Under the Curve (AUC).
Upon comparative analysis, it was observed that the model trained
with a larger proportion of data (Training 90%, Testing 10%)
demonstrated superior performance, achieving higher accuracy and a more
discriminative ROC curve. This exploration across different training and
testing splits provides valuable insights into the robustness and
generalization capability of the C5.0 decision tree algorithm for
predicting water potability.
Splitting the data set into two subsets: Training(70%) and
Testing(30%):
Splitting the data set into two subsets: Training(80%) and
Testing(20%):
Splitting the data set into two subsets: Training(90%) and
Testing(10%):
Comparison Criteria:
| Accuracy |
0.5820611 |
0.9686781 |
0.5935115 |
| precision |
0.58546169 |
0.005417132 |
0.6004320 |
| sensitivity |
0.97385621 |
0.9334741 |
0.9084967 |
| specificity |
0.03211009 |
0.880677 |
0.1513761 |
As shown in the comparison the best technique to choose is Gain Raio
Due to the high accuracy
Clustering
LS0tCnRpdGxlOiAiV2F0ZXIgUXVhbGl0eSBhbmQgUG90YWJpbGl0eSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgVGhpcyBjb2RlIGlzIHJ1bm5pbmcgdXNpbmcgUiBub3RlYm9vayBpbiBSU3R1ZGlvCgojIyMgR29hbHM6CgpXZSBhcmUgY29sbGVjdGluZyBhIGRhdGFzZXQgb24gd2F0ZXIgcXVhbGl0eSB0byB0cmFpbiBhIG1hY2hpbmUgbGVhcm5pbmcgbW9kZWwgZm9yIGJpbmFyeSBjbGFzc2lmaWNhdGlvbjogZGV0ZXJtaW5pbmcgd2hldGhlciB3YXRlciBpcyBzYWZlIGZvciBjb25zdW1wdGlvbiAoMSkgb3Igbm90ICgwKS4gVGhpcyBtb2RlbCB3aWxsIGhlbHAgd2l0aCB3YXRlciB0cmVhdG1lbnQgZGVjaXNpb25zIGFuZCBlbnN1cmUgY29tcGxpYW5jZSB3aXRoIHF1YWxpdHkgc3RhbmRhcmRzLiBXZSBhcHBsaWVkIGRpZmZlcmVudCBTdW1tYXJ6aXRpb24gYW5kIHBsb3R0aW5nIG1ldGhvZHMgdG8gaGVscCB1cyB0byB1bmRlcnN0YW5kIG91ciBkYXRhc2V0LCBzdWNoIGFzIHNjYXR0ZXIsIGhpc3RvZ3JhbSBhbmQgYmFyIHBsb3QuIFRoZW4sIHdlIGFwcGx5ZWQgcHJlcHJvY2VzcyBpbiBvdXIgZGF0YSB1c2luZyBkYXRhIGNsZWFuaW5nLCBkYXRhIHRyYW5zZm9ybWF0aW9uIGFuZCBmZWF0dXJlIHNlbGVjdGlvbi4KCiMjIyBDbGFzc2lmaWNhdGlvbiBhbmQgQ2x1c3RlcmluZyBHb2FsOgoKMS1jbGFzc2lmaWNhdGlvbiBpbiB0aGlzIGRhdGFzZXQgaXMgdG8gYnVpbGQgYSBwcmVkaWN0aXZlIG1vZGVsIHRoYXQgY2FuIGNsYXNzaWZ5IHdhdGVyIHNhbXBsZXMgaW50byB0d28gY2F0ZWdvcmllczogcG90YWJsZSAoc3VpdGFibGUgZm9yIGNvbnN1bXB0aW9uKSBvciBub24tcG90YWJsZSAobm90IHN1aXRhYmxlIGZvciBjb25zdW1wdGlvbikuCgoyLWNsdXN0ZXJpbmcgaW4gdGhpcyBkYXRhc2V0IGlzIHRvIGlkZW50aWZ5IG5hdHVyYWwgZ3JvdXBpbmdzIG9yIGNsdXN0ZXJzIHdpdGhpbiB0aGUgd2F0ZXIgc2FtcGxlcyBiYXNlZCBvbiB0aGVpciBxdWFsaXR5IHBhcmFtZXRlcnMuCgojIyMgU291cmNlIG9mIHRoZSBkYXRhc2V0OgoKS2FnZ2xlCgojIyMgbGluayBvZiB0aGUgZGF0YXNldDoKCjxodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFzZXRzL3VvbTE5MDM0NmEvd2F0ZXItcXVhbGl0eS1hbmQtcG90YWJpbGl0eT4KCgojIGxpYnJhcnk6CmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygiY2FyZXQiKQojaW5zdGFsbC5wYWNrYWdlcygiZ2xtbmV0IikKI2luc3RhbGwucGFja2FnZXMoIkJvcnV0YSIpCiNpbnN0YWxsLnBhY2thZ2VzKCJtbGJlbmNoIikKI2luc3RhbGwucGFja2FnZXMoInJhbmRvbUZvcmVzdCIpCmxpYnJhcnkob3V0bGllcnMpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobWxiZW5jaCkKbGlicmFyeShjYXJldCkKbGlicmFyeShnbG1uZXQpCmxpYnJhcnkoQm9ydXRhKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KHBST0MpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoY2FyZXQpCmxpYnJhcnkocGFydHkpCmxpYnJhcnkocGFydHlraXQpCmxpYnJhcnkoUldla2EpCmxpYnJhcnkoQzUwKQpsaWJyYXJ5KHByaW50cikKbGlicmFyeShycGFydCkKbGlicmFyeShycGFydC5wbG90KQoKZ2V0d2QoKQojc2V0d2QoIi9Vc2Vycy9tYWhheWllL0Rlc2t0b3AvMzI2cCIpCiNnZXR3ZCgpCgp3YXRlcl9wb3RhYmlsaXR5ID0gcmVhZC5jc3YoJ0RhdGFzZXQvd2F0ZXJfcG90YWJpbGl0eS5jc3YnKQoKc3RyKHdhdGVyX3BvdGFiaWxpdHkpCmBgYAoKCiMjIyBzYW1wbGUgb2YgZGF0YQoKc2FtcGxlIG9mIHJhdyBkYXRhc2V0KGZpcnN0IDEwIHJvd3MpOgpgYGB7cn0KCmhlYWQod2F0ZXJfcG90YWJpbGl0eSwxMCkKYGBgCgpzYW1wbGUgb2YgcmF3IGRhdGFzZXQobGFzdCAxMCByb3dzKToKYGBge3J9CnRhaWwod2F0ZXJfcG90YWJpbGl0eSwgMTApCmBgYAoKRml2ZSBudW1iZXIgc3VtbWFyeSBvZiBlYWNoIGF0dHJpYnV0ZSBpbiBvdXIgZGF0YXNldDoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSkKYGBgCgojIyMgTnVtYmVyIG9mIGNvbHVtbiBhbmQgcm93cwoKYGBge3J9CmRpbSh3YXRlcl9wb3RhYmlsaXR5KQpgYGAKCiMjIyMgU2FtcGxlIG9mIFdhdGVyX3BvdGFiaWxpdHkgZGF0YXNldAoKVGhpcyBpcyBhIHNhbXBsZSBvZiB0aGUgZGF0YXNldCB0byBoZWxwIHRvIHVuZGVyc3RhbmQgaG93IGl0IGlzIHN0cnVjdHVyZWQgYW5kIG9yZ2FuaXplZAoKYGBge3J9ClZpZXcod2F0ZXJfcG90YWJpbGl0eSkKc2FtcGxlKHdhdGVyX3BvdGFiaWxpdHkpCmBgYAoKCiMjIyBDaGVja2luZyBmb3IgbWlzc2luZyB2YWx1ZXM6CgpUaGUgYWJzZW5jZSBvZiBkYXRhIGluIGNlcnRhaW4gdmFyaWFibGVzIG9yIGNvbHVtbnMgaW4gYSBkYXRhc2V0IGlzIHJlZmVycmVkIHRvIGFzIG1pc3Npbmcgb3IgbnVsbCB2YWx1ZXMgZHVlIHRvIHZhcmlvdXMgcmVhc29ucy4gSXQgY2FuIGhhdmUgYSBuZWdhdGl2ZSBpbXBhY3Qgb24gdGhlIGRhdGFzZXQncyBlZmZpY2llbmN5IGFuZCB0aGUgaW5mb3JtYXRpb24gdGhhdCBjYW4gYmUgdGFrZW4gZnJvbSBpdCBsYXRlciwgc28gd2UgY2hlY2tlZCB0byBzZWUgd2hldGhlciBvdXIgZGF0YSBoYWQgbWlzc2luZyBvciBudWxsIHZhbHVlcyBhbmQgZWxpbWluYXRlZCB0aGVzZSByb3dzIHRvIHByb2R1Y2UgYSBtb3JlIGVmZmljaWVudCBkYXRhc2V0LgoKZmlyc3Qgd2UgY2hlY2tlZCBmb3IgbWlzc2luZyB2YWx1ZSB0byBlbnN1cmVzIGFjY3VyYXRlIHN0YXRpc3RpY3MsIHJlbGlhYmxlIHZpc3VhbGl6YXRpb25zLCBhbmQgZ3VpZGVzIGRlY2lzaW9ucyBvbiBpbXB1dGF0aW9uIG9yIHJlbW92YWwgb2YgbWlzc2luZyBkYXRhLgoKYGBge3J9CmRpbSh3YXRlcl9wb3RhYmlsaXR5KQpzdW0oaXMubmEod2F0ZXJfcG90YWJpbGl0eSkpCmBgYAoKIyMjIFJlbW92ZSByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMKCmBgYHtyfQpjb2xTdW1zKGlzLm5hKHdhdGVyX3BvdGFiaWxpdHkpKQp3YXRlcl9wb3RhYmlsaXR5ID0gbmEub21pdCh3YXRlcl9wb3RhYmlsaXR5KQpgYGAKCgpgYGB7cn0KY29sU3Vtcyhpcy5uYSh3YXRlcl9wb3RhYmlsaXR5KSkKVmlldyh3YXRlcl9wb3RhYmlsaXR5KQpgYGAKCiMjIyBzZWNvbmQgcmVtb3ZlIHJvd3MKCiMjIyBTdGFuZGFyZCBkZXZpYXRpb246CgpUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIGluIHN0YXRpc3RpY3MgaXMgYSBtZWFzdXJlIHVzZWQgdG8gYXNzZXNzIHRoZSBzcHJlYWQgb2YgZGF0YSBhcm91bmQgdGhlIG1lYW4uIEl0IGdpdmVzIHVzIGFuIGlkZWEgb2YgaG93IG11Y2ggdGhlIGRhdGEgcG9pbnRzIGRldmlhdGUgZnJvbSB0aGUgYXZlcmFnZS4KCmBgYHtyfQpzZCh3YXRlcl9wb3RhYmlsaXR5JFR1cmJpZGl0eSkKc2Qod2F0ZXJfcG90YWJpbGl0eSRTb2xpZHMpCnNkKHdhdGVyX3BvdGFiaWxpdHkkQ29uZHVjdGl2aXR5KQpzZCh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQpzZCh3YXRlcl9wb3RhYmlsaXR5JHBoKQpgYGAKCndlIHVlcyBpdCBmb3IgZml2ZSBjb3VsbWUgVHVyYmlkaXR5LFNvbGlkcyxDb25kdWN0aXZpdHksT3JnYW5pY19jYXJib24scGguCgojIyMgTWVhbjoKCnRoZSBhdmVyYWdlLCBpcyBhIG1lYXN1cmUgb2YgY2VudHJhbCB0ZW5kZW5jeSBpbiBzdGF0aXN0aWNzLiBJdCBpcyBjYWxjdWxhdGVkIGJ5IHN1bW1pbmcgdXAgYWxsIHRoZSB2YWx1ZXMgaW4gYSBkYXRhc2V0IGFuZCBkaXZpZGluZyBieSB0aGUgbnVtYmVyIG9mIHZhbHVlcy4gVGhlIG1lYW4gZ2l2ZXMgdXMgYSByZXByZXNlbnRhdGl2ZSB2YWx1ZSB0aGF0IGlzIHR5cGljYWxseSB1c2VkIHRvIGRlc2NyaWJlIHRoZSAidHlwaWNhbCIgdmFsdWUgaW4gYSBzZXQgb2YgZGF0YS4KCmBgYHtyfQptZWFuKHdhdGVyX3BvdGFiaWxpdHkkVHVyYmlkaXR5KQptZWFuKHdhdGVyX3BvdGFiaWxpdHkkU29saWRzKSAKbWVhbih3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSkgCm1lYW4od2F0ZXJfcG90YWJpbGl0eSRPcmdhbmljX2NhcmJvbikgCm1lYW4od2F0ZXJfcG90YWJpbGl0eSRwaCkgCmBgYAoKd2UgdWVzIGl0IGZvciBmaXZlIGNvdWxtZSBUdXJiaWRpdHksU29saWRzLENvbmR1Y3Rpdml0eSxPcmdhbmljX2NhcmJvbixwaC4KCiMjIyBNZWRpYW46CgpJdCByZXByZXNlbnRzIHRoZSBtaWRkbGUgdmFsdWUgaW4gYSBkYXRhc2V0IHdoZW4gdGhlIHZhbHVlcyBhcmUgYXJyYW5nZWQgaW4gYXNjZW5kaW5nIG9yIGRlc2NlbmRpbmcgb3JkZXIuCgpgYGB7cn0KbWVkaWFuKHdhdGVyX3BvdGFiaWxpdHkkVHVyYmlkaXR5KQptZWRpYW4od2F0ZXJfcG90YWJpbGl0eSRTb2xpZHMpCm1lZGlhbih3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSkKbWVkaWFuKHdhdGVyX3BvdGFiaWxpdHkkT3JnYW5pY19jYXJib24pCm1lZGlhbih3YXRlcl9wb3RhYmlsaXR5JHBoKQpgYGAKCndlIHVlcyBpdCBmb3IgZml2ZSBjb3VsbWUgVHVyYmlkaXR5LFNvbGlkcyxDb25kdWN0aXZpdHksT3JnYW5pY19jYXJib24scGguCgojIyMgVmFyaWFuY2U6CgpJdCBwcm92aWRlcyBpbmZvcm1hdGlvbiBhYm91dCBob3cgZmFyIGVhY2ggdmFsdWUgaW4gdGhlIGRhdGFzZXQgaXMgZnJvbSB0aGUgbWVhbi4gQSBoaWdoZXIgdmFyaWFuY2UgaW5kaWNhdGVzIGEgZ3JlYXRlciBzcHJlYWQgb2YgZGF0YSwgd2hpbGUgYSBsb3dlciB2YXJpYW5jZSBzdWdnZXN0cyB0aGF0IHRoZSBkYXRhIHBvaW50cyBhcmUgY2xvc2VyIHRvIHRoZSBtZWFuLgoKYGBge3J9CnZhcih3YXRlcl9wb3RhYmlsaXR5JFR1cmJpZGl0eSkKdmFyKHdhdGVyX3BvdGFiaWxpdHkkU29saWRzKQp2YXIod2F0ZXJfcG90YWJpbGl0eSRDb25kdWN0aXZpdHkpCnZhcih3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQp2YXIod2F0ZXJfcG90YWJpbGl0eSRwaCkKYGBgCgpBcyB5b3UgY2FuIHNlZSB0aGUgaGlnaGVzdCBWYXJpYW5jZSBTb2xpZHMsIGFuZCB0aGUgbG93ZXN0IFR1cmJpZGl0eS4KCiMjIyBTdGF0aXN0aWNhbCBNZWFzdXJlczoKCiMjIyBJbiB0aGUgZ2l2ZW4gY29kZSwgeW91J3ZlIHVzZWQgdGhlIHN1bW1hcnkgZnVuY3Rpb24gdG8gb2J0YWluIGtleSBzdGF0aXN0aWNhbCBtZWFzdXJlcyBmb3IgdmFyaWFibGVzIHN1Y2ggYXMgIkNvbmR1Y3Rpdml0eSwiICJPcmdhbmljX2NhcmJvbiwiICJIYXJkbmVzcywiIGV0Yy4sIGluIHRoZSB3YXRlcl9wb3RhYmlsaXR5IGRhdGFzZXQuIFRoZXNlIG1lYXN1cmVzIGluY2x1ZGUgbWluaW11bSwgMXN0IHF1YXJ0aWxlLCBtZWRpYW4sIG1lYW4sIDNyZCBxdWFydGlsZSwgYW5kIG1heGltdW0gdmFsdWVzLCBvZmZlcmluZyBhIHN1Y2NpbmN0IG92ZXJ2aWV3IG9mIGVhY2ggdmFyaWFibGUncyBkaXN0cmlidXRpb24gYW5kIGNoYXJhY3RlcmlzdGljcy4gVGhpcyBwcm92aWRlcyBlc3NlbnRpYWwgaW5zaWdodHMgZm9yIHRoZSBpbml0aWFsIGV4cGxvcmF0aW9uIGFuZCB1bmRlcnN0YW5kaW5nwqBvZsKgdGhlwqBkYXRhc2V0LgpXaXRoIHVzaW5nIG1pbmltdW0sIG1heGltdW0sIG1lYW4sIG1lZGlhbiBsYXdzIGl0IGhlbHBzIHRvIHByb3ZpZGUgYW4gb3ZlcnZpZXcgb2YgdGhlIGRhdGEncyBrZXkgY2hhcmFjdGVyaXN0aWNzCgpgYGB7cn0Kc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSkKc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkSGFyZG5lc3MpCnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRTb2xpZHMpCnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRDaGxvcmFtaW5lcykKc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JFBvdGFiaWxpdHkpCnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRTdWxmYXRlKQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkVHJpaGFsb21ldGhhbmVzKQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkVHVyYmlkaXR5KQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkcGgpCmBgYAoKIyBEYXRhIFRyYW5zZm9ybWF0aW9uOgoKVGhpcyBzdGVwIGludm9sdmVkIHRyYW5zZm9ybWluZyB0aGUgY2xhc3MgbGFiZWwsIFBvdGFiaWxpdHksIGludG8gY2F0ZWdvcmljYWwgZGF0YS4gV2UgY2hhbmdlZCB0aGUgbnVtZXJpYyBkYXRhIHRvICdOb3QgUG90YWJsZScgYW5kICdQb3RhYmxlJyB0byBpbmRpY2F0ZSB3aGV0aGVyIHRoZSB3YXRlciBpcyBzYWZlIGZvciBodW1hbiBjb25zdW1wdGlvbiwgd2hlcmUgMSByZXByZXNlbnRzICdQb3RhYmxlJywgYW5kIDAgcmVwcmVzZW50cyAnTm90IFBvdGFibGUuCgpgYGB7cn0Kd2F0ZXJfcG90YWJpbGl0eSRQb3RhYmlsaXR5W3dhdGVyX3BvdGFiaWxpdHkkUG90YWJpbGl0eSA9PSAnMCddIDwtICdOb3QgUG90YWJsZScKd2F0ZXJfcG90YWJpbGl0eSRQb3RhYmlsaXR5W3dhdGVyX3BvdGFiaWxpdHkkUG90YWJpbGl0eSA9PSAnMSddIDwtICdQb3RhYmxlJwoKd2F0ZXJfcG90YWJpbGl0eSRQb3RhYmlsaXR5IDwtIGFzLmZhY3Rvcih3YXRlcl9wb3RhYmlsaXR5JFBvdGFiaWxpdHkpCnRhYmxlKHdhdGVyX3BvdGFiaWxpdHkkUG90YWJpbGl0eSkKCmBgYAoKYGBge3J9CnByaW50KHdhdGVyX3BvdGFiaWxpdHkpCmBgYAoKIyMjIG91dGxpZXJzOgoKVGhleSBhcmUgb2JzZXJ2YXRpb25zIHRoYXQgbGllIGZhciBhd2F5IGZyb20gdGhlIG1ham9yaXR5IG9mIHRoZSBkYXRhLiBPdXRsaWVycyBjYW4gb2NjdXIgZHVlIHRvIHZhcmlvdXMgcmVhc29ucyBzdWNoIGFzIG1lYXN1cmVtZW50IGVycm9ycywgZXhwZXJpbWVudGFsIGFub21hbGllcywgb3IgZ2VudWluZSBleHRyZW1lIHZhbHVlcy4KCiMjYmVmb3JlIHJlbW92aW5nIG91dGxpZXI6CgpgYGB7cn0KZGltKHdhdGVyX3BvdGFiaWxpdHkpCmhlYWQod2F0ZXJfcG90YWJpbGl0eSkKYGBgCgojIyMjIHJlbW92aW5nIG91dGxpZXJzOgoKUmVtb3Zpbmcgb3V0bGllcnMgZnJvbSBhIGRhdGFzZXQgaXMgY3JpdGljYWwgZm9yIGFzc3VyaW5nIHRoZSBxdWFsaXR5IGFuZCByZWxpYWJpbGl0eSBvZiBzdGF0aXN0aWNhbCBhbmFseXNpcyBhbmQgbWFjaGluZSBsZWFybmluZyBtb2RlbHMuIFdlIGZvdW5kIGFsbCBvdXRsaWVycyBpbiB0aGUgbnVtZXJpY2FsIGF0dHJpYnV0ZXMgYW5kIHN1YnNlcXVlbnRseSBlbGltaW5hdGVkIHRoZSByb3dzIGNvbnRhaW5pbmcgdGhlIG91dGxpZXJzLgoKIyMjIC0gcGgKCmBgYHtyfQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkcGgpCnF1YXJ0aWxlcyA8LSBxdWFudGlsZSh3YXRlcl9wb3RhYmlsaXR5JHBoLCBwcm9icyA9IGMoLjI1LCAuNzUpLCBuYS5ybSA9IEZBTFNFKQpxdWFydGlsZXMKaXFyIDwtIElRUih3YXRlcl9wb3RhYmlsaXR5JHBoKQppcXIKbG93ZXIgPC0gcXVhcnRpbGVzWzFdIC0gMS41Kmlxcgpsb3dlcgp1cHBlciA8LSBxdWFydGlsZXNbMl0gKyAxLjUqaXFyCnVwcGVyCgpib3hwbG90KHBoIH4gUG90YWJpbGl0eSwgZGF0YSA9IHdhdGVyX3BvdGFiaWxpdHkpCgpyZXBlYXQgewogIG91dF92YWwgPC0gYm94cGxvdCh3YXRlcl9wb3RhYmlsaXR5JHBoLCB5bGFiID0gJ3BoJykkb3V0CiAgb3V0X3ZhbAogIG91dF9yb3dzIDwtIHdoaWNoKHdhdGVyX3BvdGFiaWxpdHkkcGggJWluJSBjKG91dF92YWwpKQogIG91dF9yb3dzCiAgCiAgaWYoc3VtKG91dF9yb3dzKSA+IDApIHdhdGVyX3BvdGFiaWxpdHkgPC0gd2F0ZXJfcG90YWJpbGl0eVstb3V0X3Jvd3MsXQogIGVsc2Uge2JyZWFrfQp9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRwaCkKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYAoKIyMjIC1IYXJkbmVzcwoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRIYXJkbmVzcykKcXVhcnRpbGVzIDwtIHF1YW50aWxlKHdhdGVyX3BvdGFiaWxpdHkkSGFyZG5lc3MsIHByb2JzID0gYyguMjUsIC43NSksIG5hLnJtID0gRkFMU0UpCnF1YXJ0aWxlcwppcXIgPC0gSVFSKHdhdGVyX3BvdGFiaWxpdHkkSGFyZG5lc3MpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoSGFyZG5lc3MgfiBQb3RhYmlsaXR5LCBkYXRhID0gd2F0ZXJfcG90YWJpbGl0eSkKCnJlcGVhdCB7CiAgb3V0X3ZhbCA8LSBib3hwbG90KHdhdGVyX3BvdGFiaWxpdHkkSGFyZG5lc3MsIHlsYWIgPSAnSGFyZG5lc3MnKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRIYXJkbmVzcyAlaW4lIGMob3V0X3ZhbCkpCiAgb3V0X3Jvd3MKCiAgaWYoc3VtKG91dF9yb3dzKSA+IDApIHdhdGVyX3BvdGFiaWxpdHkgPC0gd2F0ZXJfcG90YWJpbGl0eVstb3V0X3Jvd3MsXQogIGVsc2Uge2JyZWFrfQp9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRIYXJkbmVzcykKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYAoKIyMjIC1Tb2xpZHMKCmBgYHtyfQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkU29saWRzKQpxdWFydGlsZXMgPC0gcXVhbnRpbGUod2F0ZXJfcG90YWJpbGl0eSRTb2xpZHMsIHByb2JzID0gYyguMjUsIC43NSksIG5hLnJtID0gRkFMU0UpCnF1YXJ0aWxlcwppcXIgPC0gSVFSKHdhdGVyX3BvdGFiaWxpdHkkU29saWRzKQppcXIKbG93ZXIgPC0gcXVhcnRpbGVzWzFdIC0gMS41Kmlxcgpsb3dlcgp1cHBlciA8LSBxdWFydGlsZXNbMl0gKyAxLjUqaXFyCnVwcGVyCgpib3hwbG90KFNvbGlkcyB+IFBvdGFiaWxpdHksIGRhdGEgPSB3YXRlcl9wb3RhYmlsaXR5KQoKcmVwZWF0IHsKICBvdXRfdmFsIDwtIGJveHBsb3Qod2F0ZXJfcG90YWJpbGl0eSRTb2xpZHMsIHlsYWIgPSAnU29saWRzJykkb3V0CiAgb3V0X3ZhbAogIG91dF9yb3dzIDwtIHdoaWNoKHdhdGVyX3BvdGFiaWxpdHkkU29saWRzICVpbiUgYyhvdXRfdmFsKSkKICBvdXRfcm93cwoKICBpZihzdW0ob3V0X3Jvd3MpID4gMCkgd2F0ZXJfcG90YWJpbGl0eSA8LSB3YXRlcl9wb3RhYmlsaXR5Wy1vdXRfcm93cyxdCiAgZWxzZSB7YnJlYWt9Cn0Kc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JFNvbGlkcykKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCmBgYAoKIyMjIC1DaGxvcmFtaW5lcwoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRDaGxvcmFtaW5lcykKcXVhcnRpbGVzIDwtIHF1YW50aWxlKHdhdGVyX3BvdGFiaWxpdHkkQ2hsb3JhbWluZXMsIHByb2JzID0gYyguMjUsIC43NSksIG5hLnJtID0gRkFMU0UpCnF1YXJ0aWxlcwppcXIgPC0gSVFSKHdhdGVyX3BvdGFiaWxpdHkkQ2hsb3JhbWluZXMpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoQ2hsb3JhbWluZXMgfiBQb3RhYmlsaXR5LCBkYXRhID0gd2F0ZXJfcG90YWJpbGl0eSkKCnJlcGVhdCB7CiAgb3V0X3ZhbCA8LSBib3hwbG90KHdhdGVyX3BvdGFiaWxpdHkkQ2hsb3JhbWluZXMsIHlsYWIgPSAnQ2hsb3JhbWluZXMnKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRDaGxvcmFtaW5lcyAlaW4lIGMob3V0X3ZhbCkpCiAgb3V0X3Jvd3MKCiAgaWYoc3VtKG91dF9yb3dzKSA+IDApIHdhdGVyX3BvdGFiaWxpdHkgPC0gd2F0ZXJfcG90YWJpbGl0eVstb3V0X3Jvd3MsXQogIGVsc2Uge2JyZWFrfQp9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRDaGxvcmFtaW5lcykKCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpgYGAKCiMjIyAtU3VsZmF0ZQoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRTdWxmYXRlKQpxdWFydGlsZXMgPC0gcXVhbnRpbGUod2F0ZXJfcG90YWJpbGl0eSRTdWxmYXRlLCBwcm9icyA9IGMoLjI1LCAuNzUpLCBuYS5ybSA9IEZBTFNFKQpxdWFydGlsZXMKaXFyIDwtIElRUih3YXRlcl9wb3RhYmlsaXR5JFN1bGZhdGUpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoU3VsZmF0ZSB+IFBvdGFiaWxpdHksIGRhdGEgPSB3YXRlcl9wb3RhYmlsaXR5KQoKcmVwZWF0IHsKICBvdXRfdmFsIDwtIGJveHBsb3Qod2F0ZXJfcG90YWJpbGl0eSRTdWxmYXRlLCB5bGFiID0gJ1N1bGZhdGUnKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRTdWxmYXRlICVpbiUgYyhvdXRfdmFsKSkKICBvdXRfcm93cwoKICBpZihzdW0ob3V0X3Jvd3MpID4gMCkgd2F0ZXJfcG90YWJpbGl0eSA8LSB3YXRlcl9wb3RhYmlsaXR5Wy1vdXRfcm93cyxdCiAgZWxzZSB7YnJlYWt9Cn0Kc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JFN1bGZhdGUpCgojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYGBgCgojIyMgLUNvbmR1Y3Rpdml0eQoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRDb25kdWN0aXZpdHkpCnF1YXJ0aWxlcyA8LSBxdWFudGlsZSh3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSwgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBGQUxTRSkKcXVhcnRpbGVzCmlxciA8LSBJUVIod2F0ZXJfcG90YWJpbGl0eSRDb25kdWN0aXZpdHkpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoQ29uZHVjdGl2aXR5IH4gUG90YWJpbGl0eSwgZGF0YSA9IHdhdGVyX3BvdGFiaWxpdHkpCgpyZXBlYXQgewogIG91dF92YWwgPC0gYm94cGxvdCh3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSwgeWxhYiA9ICdDb25kdWN0aXZpdHknKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRDb25kdWN0aXZpdHkgJWluJSBjKG91dF92YWwpKQogIG91dF9yb3dzCgogIGlmKHN1bShvdXRfcm93cykgPiAwKSB3YXRlcl9wb3RhYmlsaXR5IDwtIHdhdGVyX3BvdGFiaWxpdHlbLW91dF9yb3dzLF0KICBlbHNlIHticmVha30KfQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkQ29uZHVjdGl2aXR5KQoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KYGBgCgojIyMgLU9yZ2FuaWNfY2FyYm9uCgpgYGB7cn0Kc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQpxdWFydGlsZXMgPC0gcXVhbnRpbGUod2F0ZXJfcG90YWJpbGl0eSRPcmdhbmljX2NhcmJvbiwgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBGQUxTRSkKcXVhcnRpbGVzCmlxciA8LSBJUVIod2F0ZXJfcG90YWJpbGl0eSRPcmdhbmljX2NhcmJvbikKaXFyCmxvd2VyIDwtIHF1YXJ0aWxlc1sxXSAtIDEuNSppcXIKbG93ZXIKdXBwZXIgPC0gcXVhcnRpbGVzWzJdICsgMS41Kmlxcgp1cHBlcgoKYm94cGxvdChPcmdhbmljX2NhcmJvbiB+IFBvdGFiaWxpdHksIGRhdGEgPSB3YXRlcl9wb3RhYmlsaXR5KQoKcmVwZWF0IHsKICBvdXRfdmFsIDwtIGJveHBsb3Qod2F0ZXJfcG90YWJpbGl0eSRPcmdhbmljX2NhcmJvbiwgeWxhYiA9ICdPcmdhbmljX2NhcmJvbicpJG91dAogIG91dF92YWwKICBvdXRfcm93cyA8LSB3aGljaCh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uICVpbiUgYyhvdXRfdmFsKSkKICBvdXRfcm93cwoKICBpZihzdW0ob3V0X3Jvd3MpID4gMCkgd2F0ZXJfcG90YWJpbGl0eSA8LSB3YXRlcl9wb3RhYmlsaXR5Wy1vdXRfcm93cyxdCiAgZWxzZSB7YnJlYWt9Cn0Kc3VtbWFyeSh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KYGBgCgojIyMgLVRyaWhhbG9tZXRoYW5lcwoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRUcmloYWxvbWV0aGFuZXMpCnF1YXJ0aWxlcyA8LSBxdWFudGlsZSh3YXRlcl9wb3RhYmlsaXR5JFRyaWhhbG9tZXRoYW5lcywgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBGQUxTRSkKcXVhcnRpbGVzCmlxciA8LSBJUVIod2F0ZXJfcG90YWJpbGl0eSRUcmloYWxvbWV0aGFuZXMpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoVHJpaGFsb21ldGhhbmVzIH4gUG90YWJpbGl0eSwgZGF0YSA9IHdhdGVyX3BvdGFiaWxpdHkpCgpyZXBlYXQgewogIG91dF92YWwgPC0gYm94cGxvdCh3YXRlcl9wb3RhYmlsaXR5JFRyaWhhbG9tZXRoYW5lcywgeWxhYiA9ICdUcmloYWxvbWV0aGFuZXMnKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRUcmloYWxvbWV0aGFuZXMgJWluJSBjKG91dF92YWwpKQogIG91dF9yb3dzCgogIGlmKHN1bShvdXRfcm93cykgPiAwKSB3YXRlcl9wb3RhYmlsaXR5IDwtIHdhdGVyX3BvdGFiaWxpdHlbLW91dF9yb3dzLF0KICBlbHNlIHticmVha30KfQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkVHJpaGFsb21ldGhhbmVzKQoKIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KYGBgCgojIyMgLVR1cmJpZGl0eQoKYGBge3J9CnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSRUdXJiaWRpdHkpCnF1YXJ0aWxlcyA8LSBxdWFudGlsZSh3YXRlcl9wb3RhYmlsaXR5JFR1cmJpZGl0eSwgcHJvYnMgPSBjKC4yNSwgLjc1KSwgbmEucm0gPSBGQUxTRSkKcXVhcnRpbGVzCmlxciA8LSBJUVIod2F0ZXJfcG90YWJpbGl0eSRUdXJiaWRpdHkpCmlxcgpsb3dlciA8LSBxdWFydGlsZXNbMV0gLSAxLjUqaXFyCmxvd2VyCnVwcGVyIDwtIHF1YXJ0aWxlc1syXSArIDEuNSppcXIKdXBwZXIKCmJveHBsb3QoVHVyYmlkaXR5IH4gUG90YWJpbGl0eSwgZGF0YSA9IHdhdGVyX3BvdGFiaWxpdHkpCgpyZXBlYXQgewogIG91dF92YWwgPC0gYm94cGxvdCh3YXRlcl9wb3RhYmlsaXR5JFR1cmJpZGl0eSwgeWxhYiA9ICdUdXJiaWRpdHknKSRvdXQKICBvdXRfdmFsCiAgb3V0X3Jvd3MgPC0gd2hpY2god2F0ZXJfcG90YWJpbGl0eSRUdXJiaWRpdHkgJWluJSBjKG91dF92YWwpKQogIG91dF9yb3dzCgogIGlmKHN1bShvdXRfcm93cykgPiAwKSB3YXRlcl9wb3RhYmlsaXR5IDwtIHdhdGVyX3BvdGFiaWxpdHlbLW91dF9yb3dzLF0KICBlbHNlIHticmVha30KfQpzdW1tYXJ5KHdhdGVyX3BvdGFiaWxpdHkkVHVyYmlkaXR5KQpgYGAKCiMjIyBBZnRlciByZW1vdmluZyBvdXRsaWVyczoKCmBgYHtyfQpkaW0od2F0ZXJfcG90YWJpbGl0eSkKc3RyKHdhdGVyX3BvdGFiaWxpdHkpCmhlYWQod2F0ZXJfcG90YWJpbGl0eSkKYGBgCgojIyBDaGFydHM6Cgp2aXN1YWwgcmVwcmVzZW50YXRpb24gb2YgZGF0YSB0aGF0IGhlbHAgdXMgdW5kZXJzdGFuZCBhbmQgYW5hbHl6ZSBpbmZvcm1hdGlvbiBtb3JlIGVhc2lseS4gVGhleSBjYW4gYmUgdXNlZCB0byBkaXNwbGF5IHRyZW5kcywgY29tcGFyaXNvbnMsIGFuZCByZWxhdGlvbnNoaXBzIGJldHdlZW4gZGlmZmVyZW50IHZhcmlhYmxlcy4gVGhlcmUgYXJlIHZhcmlvdXMgdHlwZXMgb2YgY2hhcnRzLCBzdWNoIGFzCgojIyMgSGlzdG9ncmFtCgpUaGUgaGlzdG9ncmFtIHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgcGggaW4gdGhlIGRhdGFzZXQ7IHdlIG5vdGVkIHRoYXQgdGhlIG1ham9yaXR5IG9mIHZhbHVlcyBmYWxsIHdpdGhpbiB0aGUgdXN1YWwgcmFuZ2UsIHdoaWNoIGlzIGFib3V0IGJldHdlZW4gNiBhbmQgOCwgYnV0IGl0IGFsc28gc2hvd3Mgc2V2ZXJhbCBvdXRsaWVycy4KCmBgYHtyfQpoaXN0KHdhdGVyX3BvdGFiaWxpdHkkcGgpCmhpc3Qod2F0ZXJfcG90YWJpbGl0eSRDaGxvcmFtaW5lcykKaGlzdCh3YXRlcl9wb3RhYmlsaXR5JEhhcmRuZXNzKQpoaXN0KHdhdGVyX3BvdGFiaWxpdHkkU29saWRzKQpoaXN0KHdhdGVyX3BvdGFiaWxpdHkkU3VsZmF0ZSkKaGlzdCh3YXRlcl9wb3RhYmlsaXR5JENvbmR1Y3Rpdml0eSkKaGlzdCh3YXRlcl9wb3RhYmlsaXR5JE9yZ2FuaWNfY2FyYm9uKQpoaXN0KHdhdGVyX3BvdGFiaWxpdHkkVHJpaGFsb21ldGhhbmVzKQpoaXN0KHdhdGVyX3BvdGFiaWxpdHkkVHVyYmlkaXR5KQpgYGAKCiMjIyBCYXIgUGxvdAoKdGhlIGJhciBwbG90IHJlcHJlc2VudCBob3cgcGggbGV2ZWxzIGFmZmVjdCB3YXRlciBwb3J0YWJpbGl0eSBpbiB0aGUgZGF0YXNldCBpdCBpbmRpY2F0ZXMgdGhhdCBwaCBsZXZlbCBhYm92ZSAxMCBpcyBub3QgcG9ydGliYWwgYW5kIGh1bWFucyBjYW50IGNvbnN1bWUgaXQKCmBgYHtyfQp0YWIgPC0gd2F0ZXJfcG90YWJpbGl0eSRQb3RhYmlsaXR5ICU+JSB0YWJsZSgpCnR4dCA8LSBwYXN0ZTAodGFiKSAKYmIgPC0gd2F0ZXJfcG90YWJpbGl0eSRwaCAlPiUgdGFibGUoKSAlPiUgYmFycGxvdCggbWFpbj0ncGgnLGNvbD1jKCdwaW5rJykpCmJiIDwtIHdhdGVyX3BvdGFiaWxpdHkkUG90YWJpbGl0eSAlPiUgdGFibGUoKSAlPiUgYmFycGxvdCggbWFpbj0nUG90YWJpbGl0eScseWxhYj0nRnJlcXVlbmN5Jyxjb2w9YygncGluaycsICdsaWdodGJsdWUnKSkKdGV4dChiYiwgdGFiLzIsIGxhYmVscz10eHQsIGNleD0xKQoKYGBgCgojIyMgU2NhdHRlciBQbG90CgpUaGlzIHNjYXR0ZXIgZGVtb25zdHJhdGVzIHRoZSBjb3JyZWxhdGlvbiBhbmQgcHJvcG9ydGlvbmFsaXR5IGJldHdlZW4gdGhlIHR3byBxdWFsaXRpZXMsIGFsbG93aW5nIHVzIHRvIGVzdGFibGlzaCB3aGV0aGVyIG9yIG5vdCB0dXJiaWRpdHkgYW5kIHBIIGFyZSBjb25uZWN0ZWQuCgpgYGB7cn0Kd2l0aCh3YXRlcl9wb3RhYmlsaXR5LCBwbG90KFRyaWhhbG9tZXRoYW5lcywgcGgsIGNvbCA9IFBvdGFiaWxpdHksIHBjaCA9IGFzLm51bWVyaWMoUG90YWJpbGl0eSkpKQpgYGAKCiMjIyBSZW1vdmUgUmVkdW5kYW50IEZlYXR1cmVzOgoKVGhpcyB3aWxsIGZpbmQgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGZlYXR1cmVzIGFuZCByZXByZXNlbnQgaXQgaW4gaGVhdCBtYXAKCmBgYHtyfQpjb3JyZWxhdGlvbl9tYXRyaXggPC0gY29yKHdhdGVyX3BvdGFiaWxpdHlbLDE6OV0pCmhpZ2hfY29ycmVsYXRpb25fZmVhdHVyZXMgPC0gZmluZENvcnJlbGF0aW9uKGNvcnJlbGF0aW9uX21hdHJpeCwgY3V0b2ZmID0gMC41KQpwcmludChoaWdoX2NvcnJlbGF0aW9uX2ZlYXR1cmVzKQpoZWF0bWFwKGNvcnJlbGF0aW9uX21hdHJpeCkKYGBgCgp3ZSByZW1vdmUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIGZlYXR1cmVzIGFuZCByZXByZXNlbnQgaXQgaW4gaGVhdCBtYXAKCiMjIyBGZWF0dXJlIHNlbGVjdGlvbjoKIyMjIEZlYXR1cmUgc2VsZWN0aW9uIGlzIGRlZW1lZCB1bm5lY2Vzc2FyeSBmb3Igb3VyIGRhdGFzZXQsIGFzIGVhY2ggYXR0cmlidXRlIGlzIGRlZW1lZCB0byBwcm92aWRlIGNydWNpYWwsIGRpc3RpbmN0IGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gdGhlIGNob3NlbiB2YXJpYWJsZS4gVGhlIHJlYXNvbmluZyBiZWhpbmQgdGhpcyBkZWNpc2lvbiBpcyB0aGF0IGVsaW1pbmF0aW5nIGFueSBhdHRyaWJ1dGUgdGhyb3VnaCBmZWF0dXJlIHNlbGVjdGlvbiBjb3VsZCBwb3RlbnRpYWxseSBsZWFkIHRvIHRoZSBsb3NzIG9mIHZpdGFsIGRhdGEuIEFkZGl0aW9uYWxseSwgY2VydGFpbiBtYWNoaW5lIGxlYXJuaW5nIGFsZ29yaXRobXMgcG9zc2VzcyB0aGUgY2FwYWJpbGl0eSB0byBpZGVudGlmeSBpbnRyaWNhdGUgaW50ZXJhY3Rpb25zIGFuZCBhdHRyaWJ1dGUgY29ycmVsYXRpb25zLiBCeSBpbmNsdWRpbmcgYWxsIHZhcmlhYmxlcyBpbiB0aGUgbW9kZWwsIHdlIGFpbSB0byBlbmFibGUgdGhlIGxlYXJuaW5nIGFuZCBleHBsb2l0YXRpb24gb2YgY29tcGxleCBwYXR0ZXJucyB3aXRoaW4gdGhlIGRhdGFzZXQsIHBvdGVudGlhbGx5IGVuaGFuY2luZyBwcmVkaWN0aXZlIHBlcmZvcm1hbmNlLCBlc3BlY2lhbGx5IGNvbnNpZGVyaW5nIHRoZSBkYXRhc2V0J3Mgc3Vic3RhbnRpYWwgc2l6ZSB3aXRowqAxMMKgY29sdW1ucwoKaXQgaXMgY2hvb3NpbmcgdGhlIG1vc3QgcmVsZXZhbnQgZmVhdHVyZXMgZnJvbSBhIGRhdGFzZXQgdG8gZW5oYW5jZSBtb2RlbCBwZXJmb3JtYW5jZSwgcmVkdWNlIG92ZXJmaXR0aW5nLCBhbmQgaW1wcm92ZSBjb21wdXRhdGlvbmFsIGVmZmljaWVuY3kuCgoKUmFua2luZyBmZWF0dXJlcyBieSBpbXBvcnRhbmNlIGlzIGEgdGVjaG5pcXVlIHVzZWQgdG8gaWRlbnRpZnkgdGhlIG1vc3QgaW5mbHVlbnRpYWwgdmFyaWFibGVzIGluIGEgZGF0YXNldCBmb3IgcHJlZGljdGluZyBhIHRhcmdldCB2YXJpYWJsZS4gVGhpcyBwcm9jZXNzIGhlbHBzIHVuZGVyc3RhbmQgd2hpY2ggZmVhdHVyZXMgaW1wYWN0IHRoZSBtb2RlbCdzIHBlcmZvcm1hbmNlIG1vc3QgYnkgcmFua2luZyBmZWF0dXJlcyBieSBpbXBvcnRhbmNlLgoKUmVtb3ZpbmcgcmVkdW5kYW50IGZlYXR1cmVzIG1lYW5zIGVsaW1pbmF0aW5nIHZhcmlhYmxlcyBvciBmZWF0dXJlcyBmcm9tIGEgZGF0YXNldCB0aGF0IGRvIG5vdCBwcm92aWRlIGFkZGl0aW9uYWwgb3IgdW5pcXVlwqBpbmZvcm1hdGlvbi4KCgoKIyMjIFJhbmsgRmVhdHVyZXMgQnkgSW1wb3J0YW5jZToKCnJhbmtpbmcgZmVhdHVyZXMgYnkgaW1wb3J0YW5jZSBpcyBhIHRlY2huaXF1ZSB1c2VkIHRvIGlkZW50aWZ5IHRoZSBtb3N0IGluZmx1ZW50aWFsIHZhcmlhYmxlcyBpbiBhIGRhdGFzZXQgZm9yIHByZWRpY3RpbmcgYSB0YXJnZXQgdmFyaWFibGUuIFRoaXMgcHJvY2VzcyBoZWxwcyBpbiB1bmRlcnN0YW5kaW5nIHdoaWNoIGZlYXR1cmVzIGhhdmUgdGhlIG1vc3QgaW1wYWN0IG9uIHRoZSBtb2RlbCdzIHBlcmZvcm1hbmNlLiBCeSByYW5raW5nIGZlYXR1cmVzIGJ5IGltcG9ydGFuY2UuCgpgYGB7ciwgd2FybmluZz1GQUxTRX0KI3RyYWluIHJhbmRvbSBmb3Jlc3QgbW9kZWwgYW5kIGNhbGN1bGF0ZSBmZWF0dXJlIGltcG9ydGFuY2UKcmYgPSByYW5kb21Gb3Jlc3QoeD0gd2F0ZXJfcG90YWJpbGl0eVssMTo5XSx5PSB3YXRlcl9wb3RhYmlsaXR5WywxMF0pCnZhcl9pbXAgPC0gdmFySW1wKHJmLCBzY2FsZSA9IEZBTFNFKQojc29ydCB0aGUgc2NvcmUgaW4gZGVjcmVhc2luZyBvcmRlcgp2YXJfaW1wX2RmIDwtIGRhdGEuZnJhbWUoY2JpbmQodmFyaWFibGUgPSByb3duYW1lcyh2YXJfaW1wKSwgc2NvcmUgPSB2YXJfaW1wWywxXSkpCnZhcl9pbXBfZGYkc2NvcmUgPC0gYXMuZG91YmxlKHZhcl9pbXBfZGYkc2NvcmUpCnZhcl9pbXBfZGZbb3JkZXIodmFyX2ltcF9kZiRzY29yZSxkZWNyZWFzaW5nID0gVFJVRSksXQoKZ2dwbG90KHZhcl9pbXBfZGYsIGFlcyh4PXJlb3JkZXIodmFyaWFibGUsIHNjb3JlKSwgeT1zY29yZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3NlZ21lbnQoYWVzKHg9dmFyaWFibGUseGVuZD12YXJpYWJsZSx5PTAseWVuZD1zY29yZSkpICsKICB5bGFiKCJJbmNOb2RlUHVyaXR5IikgKwogIHhsYWIoIlZhcmlhYmxlIE5hbWUiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKIyMjIFJlY3Vyc2l2ZSBGZWF0dXJlIGVsaW1pbmF0aW9uOgoKaXMgYSBmZWF0dXJlIHNlbGVjdGlvbiB0ZWNobmlxdWUgdGhhdCByZWN1cnNpdmVseSByZW1vdmVzIGxlc3MgaW1wb3J0YW50IGZlYXR1cmVzIGZyb20gYSBtb2RlbCB1bnRpbCB0aGUgb3B0aW1hbCBzdWJzZXQgaXMgaWRlbnRpZmllZC4gSXQgaW52b2x2ZXMgcmVwZWF0ZWRseSB0cmFpbmluZyB0aGUgbW9kZWwsIHJhbmtpbmcgZmVhdHVyZXMgYmFzZWQgb24gdGhlaXIgaW1wb3J0YW5jZSwgYW5kIGVsaW1pbmF0aW5nIHRoZSBsZWFzdCBpbXBvcnRhbnQgb25lcy4KCiMgYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMgY29udHJvbCA8LSByZmVDb250cm9sKGZ1bmN0aW9ucz1yZkZ1bmNzLCBtZXRob2Q9ImN2IixudW1iZXI9MTApCiMgcmYgPC0gdHJhaW5Db250cm9sKG1ldGhvZCA9ICJjdiIsIG51bWJlciA9IDEwLCB2ZXJib3NlSXRlciA9IEZBTFNFKQojICMgcnVuIHRoZSBSRkUgYWxnb3JpdGhtCiMgcmZlX21vZGVsIDwtIHJmZSh4PSB3YXRlcl9wb3RhYmlsaXR5WywxOjldLHk9IHdhdGVyX3BvdGFiaWxpdHlbLDEwXSwgc2l6ZXM9YygxOjkpLCByZmVDb250cm9sPWNvbnRyb2wpCiMgIyBzdW1tYXJpemUgdGhlIHJlc3VsdHMKIyBwcmludChyZmVfbW9kZWwpCiMgIyBsaXN0IHRoZSBjaG9zZW4gZmVhdHVyZXMKIyBwcmVkaWN0b3JzKHJmZV9tb2RlbCkKIyAjIHBsb3QgdGhlIHJlc3VsdHMKIyBwbG90KHJmZV9tb2RlbCwgdHlwZT1jKCJnIiwgIm8iKSkKIyBgYGAKCiMjIyBEYXRhIHRyYW5zZm9ybWF0aW9uOgoKdGhlIHByb2Nlc3Mgb2YgY29udmVydGluZyBvciBtb2RpZnlpbmcgcmF3IGRhdGEgaW50byBhIGRpZmZlcmVudCBmb3JtYXQgb3Igc3RydWN0dXJlIHRvIG1ha2UgaXQgbW9yZSBzdWl0YWJsZSBmb3IgYW5hbHlzaXMgb3IgbW9kZWxpbmcKCiMjIyBOb3JtbGl6YXRpb24KCk5vcm1hbGl6YXRpb24gcmVmZXJzIHRvIHRoZSBwcm9jZXNzIG9mIHNjYWxpbmcgdmFyaWFibGVzIHRvIGhhdmUgYSBjb21tb24gcmFuZ2UuIEl0IGhlbHBzIGluIGNvbXBhcmluZyB2YXJpYWJsZXMgd2l0aCBkaWZmZXJlbnQgc2NhbGVzLgoKYGBge3J9CndwPC0gd2F0ZXJfcG90YWJpbGl0eQpub3JtYWxpemU9ZnVuY3Rpb24oeCl7cmV0dXJuICgoeC1taW4oeCkpLyhtYXgoeCkpKX0Kd3AkU29saWRzPW5vcm1hbGl6ZSh3cCRTb2xpZHMpCmBgYAoKVGhlIHNvbGlkcyBhdHRyaWJ1dGUgd2lsbCBjcmVhdGUgY3JpdGljYWwgY2hhbGxlbmdlcyBiZWNhdXNlIG9mIHRoZSB2YXN0IGFuZCBkaXZlcnRlZCB2YWx1ZXM6IG1pbiBpcyAzMjAuOSwgYW5kIG1heCBpcyA0MzE5NS41LCBzbyB3ZSBub3JtYWxpemVkIHRoZSBzb2xpZHMgYmV0d2VlbiAwIGFuZCAxIHRvIG1ha2UgdmFsdWVzIHNtYWxsZXIgYW5kIG1vcmUgcmVhc29uYWJsZS4KCiMjIyBEaXNjcmV0aXphdGlvbjoKCkRpc2NyZXRpemF0aW9uIGlzIHRoZSBwcm9jZXNzIG9mIHRyYW5zZm9ybWluZyBjb250aW51b3VzIHZhcmlhYmxlcyBpbnRvIGRpc2NyZXRlIG9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcy4gSXQgY2FuIGJlIHVzZWZ1bCBmb3IgYW5hbHl6aW5nIGRhdGEgd2l0aCBtYW55IHVuaXF1ZSB2YWx1ZXMgb3Igc2ltcGxpZnlpbmcgaXQuCgpgYGB7cn0KCndwJHBoPSBjdXQod3AkcGgsIGJyZWFrcyA9IHNlcSgzLDExLGJ5PTQpLHJpZ2h0PUZBTFNFKQp3cCRIYXJkbmVzcz0gY3V0KHdwJEhhcmRuZXNzLCBicmVha3MgPSBzZXEoMTIwLDI4MCxieT00MCkscmlnaHQ9RkFMU0UpCndwJENobG9yYW1pbmVzID0gY3V0KHdwJENobG9yYW1pbmVzLCBicmVha3MgPSBzZXEoMywxMSxieT00KSxyaWdodCA9IEZBTFNFKQp3cCRTdWxmYXRlPSBjdXQod3AkU3VsZmF0ZSwgYnJlYWtzID0gc2VxKDIyMCw0NDAsYnk9NDQpLHJpZ2h0PUZBTFNFKQp3cCRDb25kdWN0aXZpdHk9IGN1dCh3cCRDb25kdWN0aXZpdHksIGJyZWFrcyA9IHNlcSgyMDAsNzAwLGJ5PTEwMCkscmlnaHQ9RkFMU0UpCndwJE9yZ2FuaWNfY2FyYm9uPSBjdXQod3AkT3JnYW5pY19jYXJib24sIGJyZWFrcyA9IHNlcSg0LDI0LGJ5PTQpLHJpZ2h0PUZBTFNFKQp3cCRUcmloYWxvbWV0aGFuZXM9IGN1dCh3cCRUcmloYWxvbWV0aGFuZXMsIGJyZWFrcyA9IHNlcSgyMCwxMTAsYnk9MTApLHJpZ2h0PUZBTFNFKQp3cCRUdXJiaWRpdHk9IGN1dCh3cCRUdXJiaWRpdHksIGJyZWFrcyA9IHNlcSgxLDcsYnk9MikscmlnaHQ9RkFMU0UpCgpwcmludCh3cCkKYGBgCgpUaGVyZWZvcmUsIHdlIHRyYW5zZm9ybWVkIHRoZSBjb250aW51b3VzIHZhbHVlcyBvZiB0aGUgbnVtZXJpYyBhdHRyaWJ1dGVzIGludG8gaW50ZXJ2YWxzIGJ5IGRpdmlkaW5nIHRoZSB2YWx1ZXMgdG8gZmFsbCBvbiBvbmUgb2YgdGhlIHBvc3NpYmxlIGludGVydmFsIGxhYmVscyBieSBkaXNjcmV0aXphdGlvbi4gVGhlIHZhbHVlcyB3aWxsIGJlIG1lYW5pbmdmdWwgYW5kIHNpbXBsZXIgdG8gY2xhc3NpZnkgb3IgcGVyZm9ybSBvdGhlciBtZXRob2RzIHRvIGhlbHAgdXMgbGF0ZXIgaW4gb3VyIG1vZGVsLiBTbywgSW4gVHJpaGFsb21ldGhhbmVzLCB3ZSBpbnRlcnZhbHMgYnkgZGl2aWRpbmcgdGhlIHZhbHVlcyBieSAxMCB0byBoYXZlIGxhYmVscyB3aXRoIGVxdWFsIHdpZHRoIDogWzIwLDMwKSBbMzAsNDApIFs0MCw1MCkgWzUwLDYwKSBbNjAsNzApIFs3MCw4MCkgWzgwLDkwKSBbOTAsMTAwKSBbMTAwLDExMCkuCgojIyMgIyNFbmNvZGluZwoKZW5jb2RpbmcgaXMgdGhlIHByb2Nlc3Mgb2YgY29udmVydGluZyBjaGFyYWN0ZXJzIG9yIHN0cmluZ3MgaW50byBhIHNwZWNpZmljIGVuY29kaW5nIGZvcm1hdC4gU2luY2Ugd2UgZG9uJ3QgaGF2ZSBhIE5vbWluYWwgYXR0cmlidXRlIGluIG91ciBkYXRhYmFzZSB3ZSBjb3VsZG4ndCBpbXBsZW1lbnQgaXQuCmBgYHtyfQp3cApgYGAKCiMjIGNsYXNzZmljYXRpb24gYW5kIGNsdXN0cmluZyBJbiBvdXIgZGF0YXNldCBleHBsb3JhdGlvbiwgd2UgZW1wbG95ZWQgYm90aCBzdXBlcnZpc2VkIGFuZCB1bnN1cGVydmlzZWQgbGVhcm5pbmcgbWV0aG9kb2xvZ2llcyB0aHJvdWdoIGNsYXNzaWZpY2F0aW9uIGFuZCBjbHVzdGVyaW5nIHRlY2huaXF1ZXMuCgogRm9yIGNsYXNzaWZpY2F0aW9uLCB3ZSBjaG9zZSB0aGUgZGVjaXNpb24gdHJlZSBhbGdvcml0aG0sIGEgcmVjdXJzaXZlIGFwcHJvYWNoIGNvbnN0cnVjdGluZyBhIHRyZWUgc3RydWN0dXJlIHdpdGggbGVhZiBub2RlcyBzaWduaWZ5aW5nIGZpbmFsIGRlY2lzaW9ucy4gVGhlIG9iamVjdGl2ZSB3YXMgdG8gcHJlZGljdCB0aGUgY2xhc3MgbGFiZWwgKHBvdGFiaWxpdHkpLCB3aXRoIHZhbHVlcyAwIG9yIDEsIGJhc2VkIG9uIGF0dHJpYnV0ZXMgbGlrZSBwSCwgSGFyZG5lc3MsIFNvbGlkcywgQ2hsb3JhbWluZXMsIFN1bGZhdGUsIENvbmR1Y3Rpdml0eSwgT3JnYW5pY19jYXJib24sIFRyaWhhbG9tZXRoYW5lcywgYW5kIFR1cmJpZGl0eS4gVGhlIGRhdGFzZXQgdW5kZXJ3ZW50IGRpdmlzaW9uIGludG8gdHJhaW5pbmcgYW5kIHRlc3Rpbmcgc2V0cyBmb3IgY29uc3RydWN0aW5nIGFuZCBldmFsdWF0aW5nIHRoZSBkZWNpc2lvbiB0cmVlLiBNb2RlbCBldmFsdWF0aW9uIGVuY29tcGFzc2VkIG1ldHJpY3MgbGlrZSBhY2N1cmFjeSBhbmQgY29zdC1zZW5zaXRpdmUgbWVhc3VyZXMsIGdhdWdlZCB1c2luZyBhIGNvbmZ1c2lvbiBtYXRyaXguIE91ciB0b29sa2l0IGluY2x1ZGVkIHBhY2thZ2VzIHN1Y2ggYXMgJ3BhcnR5JyBhbmQgJ2NhcmV0LCcgaW5jb3Jwb3JhdGluZyBtZXRob2RzIGxpa2UgJ3NhbXBsZScgZm9yIGRhdGEgc3BsaXR0aW5nLCAnY3RyZWUnIGZvciBkZWNpc2lvbiB0cmVlIGNvbnN0cnVjdGlvbiwgJ3ByZWRpY3QnIGZvciB0ZXN0aW5nIHByZWRpY3Rpb25zLCBhbmQgJ2NvbmZ1c2lvbk1hdHJpeCcgZm9yIG1vZGVsIGV2YWx1YXRpb24uCgogSW4gdGhlIHVuc3VwZXJ2aXNlZCBjbHVzdGVyaW5nIHBoYXNlLCB3ZSBleGNsdWRlZCB0aGUgY2xhc3MgbGFiZWwgYXR0cmlidXRlICJwb3RhYmlsaXR5IiBhbmQgdXRpbGl6ZWQgbnVtZXJpYyBhdHRyaWJ1dGVzIHN1Y2ggYXMgcEgsIEhhcmRuZXNzLCBTb2xpZHMsIENobG9yYW1pbmVzLCBTdWxmYXRlLCBDb25kdWN0aXZpdHksIE9yZ2FuaWNfY2FyYm9uLCBUcmloYWxvbWV0aGFuZXMsIGFuZCBUdXJiaWRpdHkuIEVtcGxveWluZyB0aGUgSy1tZWFucyBhbGdvcml0aG0sIGNsdXN0ZXJzIHdlcmUgZm9ybWVkLCBlYWNoIHJlcHJlc2VudGVkIGJ5IGEgY2VudGVyIHBvaW50LCBhbmQgb2JqZWN0cyB3ZXJlIGFzc2lnbmVkIHRvIHRoZSBuZWFyZXN0IGNsdXN0ZXIuIEZvciB0aGlzIHBoYXNlLCB3ZSBtYWRlIHVzZSBvZiBwYWNrYWdlcyBzdWNoIGFzICdjbHVzdGVyJyBhbmQgJ2ZhY3RvZXh0cmEsJyBpbmNvcnBvcmF0aW5nIG1ldGhvZHMgbGlrZSAnc2NhbGUoKScgZm9yIGRhdGEgc2NhbGluZywgJ0ttZWFucygpJyBmb3IgY2x1c3RlciBjcmVhdGlvbi4KCiBDbHVzdGVyIHZhbGlkYXRpb24gd2FzIHBlcmZvcm1lZCB1c2luZyB0aGUgJ3NpbGhvdWV0dGUoKScgbWV0aG9kIHRvIGNhbGN1bGF0ZSBhdmVyYWdlcyBmb3IgZWFjaCBjbHVzdGVyLiBJbiBib3RoIHN1cGVydmlzZWQgYW5kIHVuc3VwZXJ2aXNlZCB0ZWNobmlxdWVzLCB3ZSBtYWludGFpbmVkIHJlc3VsdCBjb25zaXN0ZW5jeSBieSBlbXBsb3lpbmcgdGhlICdzZXQuc2VlZCgpJyBtZXRob2Qgd2l0aCB0aGUgc2FtZSByYW5kb20gbnVtYmVyIHdoZW4gZXhwZXJpbWVudGluZyB3aXRoIGRpZmZlcmVudMKgZGF0YXNldMKgc2l6ZXMuCgoKI1RyYWluaW5nIHRlY2huaXF1ZQoKIEluIHRoZSBwcm92aWRlZCBjb2RlLCB3ZSBzeXN0ZW1hdGljYWxseSBhZGRyZXNzZWQgb3V0bGllcnMgaW4gbXVsdGlwbGUgY29sdW1ucyBvZiBvdXIgZGF0YXNldC4gQmVnaW5uaW5nIHdpdGggYSBzdW1tYXJ5IG9mIGVhY2ggY29sdW1uJ3Mgc3RhdGlzdGljcywgaW5jbHVkaW5nIHF1YXJ0aWxlcyBhbmQgdGhlIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUiksIHdlIGVzdGFibGlzaGVkIG91dGxpZXIgZGV0ZWN0aW9uIGxpbWl0cy4gQSB2aXN1YWwgYXNzZXNzbWVudCB3YXMgY29uZHVjdGVkIHVzaW5nIGJveHBsb3RzLCBjYXRlZ29yaXplZCBieSByZWxldmFudCB2YXJpYWJsZXMgc3VjaCBhcyAiUG90YWJpbGl0eS4iIEEgbG9vcCB3YXMgaW1wbGVtZW50ZWQgdG8gaXRlcmF0aXZlbHkgaWRlbnRpZnkgYW5kIHJlbW92ZSBvdXRsaWVycyBpbiBlYWNoIGNvbHVtbiwgZW5zdXJpbmcgYSByb2J1c3QgY2xlYW5zaW5nIHByb2Nlc3MuIFRoZSBmaW5hbCBzdGVwIGludm9sdmVkIHN1bW1hcml6aW5nIHRoZSBjb2x1bW5zIHBvc3Qtb3V0bGllciByZW1vdmFsLCBvZmZlcmluZyBpbnNpZ2h0cyBpbnRvIHRoZSBpbXBhY3Qgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiBlYWNoIHZhcmlhYmxlLiBUaGlzIGNvbXByZWhlbnNpdmUgYXBwcm9hY2ggd2FzIGFwcGxpZWQgdW5pZm9ybWx5IHRvIGFsbCBkYXRhc2V0IGNvbHVtbnMsIHByb21vdGluZyBjb25zaXN0ZW5jeSBpbiB0aGUgb3V0bGllci1oYW5kbGluZ8KgcHJvY2Vzcy4KCgojIyMgSW5mb3JtYXRpb24gZ2FpbiAoSUQzKQpJbiB0aGlzIFIgY29kZSwgdGhlIGRhdGFzZXQgIHVuZGVyZ29lcyBhIHByb2Nlc3Mgb2YgdHJhaW5pbmcgYW5kIHRlc3RpbmcgdXNpbmcgdGhlIElEMyBhbGdvcml0aG0gZm9yIGRlY2lzaW9uIHRyZWUgY2xhc3NpZmljYXRpb24uIFRoZSBkYXRhIGlzIHN1Y2Nlc3NpdmVseSBzcGxpdCBpbnRvIHRyYWluaW5nIHNldHMgb2YgNzAlLCA4MCUsIGFuZCA5MCUsIHdpdGggY29ycmVzcG9uZGluZyB0ZXN0aW5nIHNldHMgb2YgMzAlLCAyMCUsIGFuZCAxMCUuIFRoZSBkZWNpc2lvbiB0cmVlIG1vZGVscyBhcmUgdHJhaW5lZCBvbiB0aGVzZSBzdWJzZXRzLCB1dGlsaXppbmcgZmVhdHVyZXMgc3VjaCBhcyBwSCwgaGFyZG5lc3MsIHNvbGlkcywgY2hsb3JhbWluZXMsIHN1bGZhdGUsIGNvbmR1Y3Rpdml0eSwgb3JnYW5pYyBjYXJib24sIHRyaWhhbG9tZXRoYW5lcywgYW5kIHR1cmJpZGl0eSB0byBwcmVkaWN0IHdhdGVyIHBvdGFiaWxpdHkuCgpGb3IgZWFjaCBzcGxpdCwgdGhlIGRlY2lzaW9uIHRyZWUgbW9kZWxzIGFyZSBldmFsdWF0ZWQgb24gdGhlaXIgcmVzcGVjdGl2ZSB0ZXN0aW5nIHNldHMsIGFuZCBwZXJmb3JtYW5jZSBtZXRyaWNzIHN1Y2ggYXMgY29uZnVzaW9uIG1hdHJpY2VzIGFuZCBhY2N1cmFjeSBhcmUgY29tcHV0ZWQuIEFkZGl0aW9uYWxseSwgUmVjZWl2ZXIgT3BlcmF0aW5nIENoYXJhY3RlcmlzdGljIChST0MpIGN1cnZlcyBhcmUgZ2VuZXJhdGVkLCBwcm92aWRpbmcgaW5zaWdodHMgaW50byB0aGUgbW9kZWxzJyBkaXNjcmltaW5hdGlvbiBjYXBhYmlsaXRpZXMuIFRoZSBBcmVhIFVuZGVyIHRoZSBDdXJ2ZSAoQVVDKSBpcyBjYWxjdWxhdGVkIGFzIGEgcXVhbnRpdGF0aXZlIG1lYXN1cmUgb2YgbW9kZWwgcGVyZm9ybWFuY2UuIFRoaXMgY29tcHJlaGVuc2l2ZSBhcHByb2FjaCBlbmFibGVzIGEgc3lzdGVtYXRpYyBleHBsb3JhdGlvbiBvZiB0aGUgSUQzIGRlY2lzaW9uIHRyZWUncyBlZmZlY3RpdmVuZXNzIGluIHByZWRpY3Rpbmcgd2F0ZXIgcG90YWJpbGl0eSB1bmRlciB2YXJ5aW5nIHRyYWluaW5nIGFuZCB0ZXN0aW5nwqBzY2VuYXJpb3MuCgoKU3BsaXR0aW5nIHRoZSBkYXRhIHNldCBpbnRvIHR3byBzdWJzZXRzOiBUcmFpbmluZyg3MCUpIGFuZCBUZXN0aW5nKDMwJSk6CmBgYHtyfQpzZXQuc2VlZCgxOTU4KQppbmQgPC0gc2FtcGxlKDIsIG5yb3cod3ApLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC43LCAwLjMpKQp0cmFpbi5kYXRhIDwtIHdwW2luZCA9PSAxLCBdCnRlc3QuZGF0YSA8LSB3cFtpbmQgPT0gMiwgXQp0cmFpbi5kYXRhJFBvdGFiaWxpdHkgPC0gYXMuZmFjdG9yKHRyYWluLmRhdGEkUG90YWJpbGl0eSkKdGVzdC5kYXRhJFBvdGFiaWxpdHkgPC0gYXMuZmFjdG9yKHRlc3QuZGF0YSRQb3RhYmlsaXR5KQoKCm15Rm9ybXVsYSA8LSBQb3RhYmlsaXR5IH4gcGgrSGFyZG5lc3MrU29saWRzK0NobG9yYW1pbmVzK1N1bGZhdGUrQ29uZHVjdGl2aXR5K09yZ2FuaWNfY2FyYm9uK1RyaWhhbG9tZXRoYW5lcytUdXJiaWRpdHkKI215Rm9ybXVsYSA8LSBQb3RhYmlsaXR5IH4gcGgrSGFyZG5lc3MrU29saWRzK0NobG9yYW1pbmVzK1N1bGZhdGUKCgptLmN0cmVlIDwtIGN0cmVlKG15Rm9ybXVsYSwgZGF0YSA9IHRyYWluLmRhdGEpCnRhYmxlKHByZWRpY3QobS5jdHJlZSksIHRyYWluLmRhdGEkUG90YWJpbGl0eSkKCnByaW50KG0uY3RyZWUpCnBsb3QobS5jdHJlZSwgdHlwZT0ic2ltcGxlIikKCnRlc3RQcmVkIDwtIHByZWRpY3QobS5jdHJlZSwgbmV3ZGF0YSA9IHRlc3QuZGF0YSkKcmVzdWx0PC10YWJsZSh0ZXN0UHJlZCwgdGVzdC5kYXRhJFBvdGFiaWxpdHkpCgoKY29fcmVzdWx0IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHQpCnByaW50KGNvX3Jlc3VsdCkKYXMubWF0cml4KGNvX3Jlc3VsdCwgd2hhdCA9ICJjbGFzc2VzIikKYWNjIDwtIGNvX3Jlc3VsdCRvdmVyYWxsWyJBY2N1cmFjeSJdCmFjYyoxMDAKCgpwcmVkX3Byb2JzIDwtIGFzLm51bWVyaWMocHJlZGljdChtLmN0cmVlLCBuZXdkYXRhID0gdGVzdC5kYXRhLCB0eXBlID0gInJlc3BvbnNlIikpCmJpbmFyeV9vdXRjb21lIDwtIGFzLm51bWVyaWModGVzdC5kYXRhJFBvdGFiaWxpdHkgPT0gIlBvdGFibGUiKQojIFJPQyBjdXJ2ZQpyb2NfY3VydmUgPC0gcm9jKGJpbmFyeV9vdXRjb21lLCBwcmVkX3Byb2JzKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCmBgYAoKU3BsaXR0aW5nIHRoZSBkYXRhIHNldCBpbnRvIHR3byBzdWJzZXRzOiBUcmFpbmluZyg4MCUpIGFuZCBUZXN0aW5nKDIwJSk6CmBgYHtyfQoKc2V0LnNlZWQoMTk1OCkKaW5kIDwtIHNhbXBsZSgyLCBucm93KHdwKSwgcmVwbGFjZSA9IFRSVUUsIHByb2IgPSBjKDAuOCwgMC4yKSkKdHJhaW4uZGF0YSA8LSB3cFtpbmQgPT0gMSwgXQp0ZXN0LmRhdGEgPC0gd3BbaW5kID09IDIsIF0KdHJhaW4uZGF0YSRQb3RhYmlsaXR5IDwtIGFzLmZhY3Rvcih0cmFpbi5kYXRhJFBvdGFiaWxpdHkpCgpteUZvcm11bGEgPC0gUG90YWJpbGl0eSB+IHBoK0hhcmRuZXNzK1NvbGlkcytDaGxvcmFtaW5lcytTdWxmYXRlK0NvbmR1Y3Rpdml0eStPcmdhbmljX2NhcmJvbitUcmloYWxvbWV0aGFuZXMrVHVyYmlkaXR5CiNteUZvcm11bGEgPC0gUG90YWJpbGl0eSB+IHBoK0hhcmRuZXNzK1NvbGlkcytDaGxvcmFtaW5lcytTdWxmYXRlCgoKbS5jdHJlZSA8LSBjdHJlZShteUZvcm11bGEsIGRhdGEgPSB0cmFpbi5kYXRhKQp0YWJsZShwcmVkaWN0KG0uY3RyZWUpLCB0cmFpbi5kYXRhJFBvdGFiaWxpdHkpCgpwcmludChtLmN0cmVlKQpwbG90KG0uY3RyZWUsIHR5cGU9InNpbXBsZSIpCgp0ZXN0UHJlZCA8LSBwcmVkaWN0KG0uY3RyZWUsIG5ld2RhdGEgPSB0ZXN0LmRhdGEpCnJlc3VsdDwtdGFibGUodGVzdFByZWQsIHRlc3QuZGF0YSRQb3RhYmlsaXR5KQoKCmNvX3Jlc3VsdCA8LSBjb25mdXNpb25NYXRyaXgocmVzdWx0KQpwcmludChjb19yZXN1bHQpCmFzLm1hdHJpeChjb19yZXN1bHQsIHdoYXQgPSAiY2xhc3NlcyIpCmFjYyA8LSBjb19yZXN1bHQkb3ZlcmFsbFsiQWNjdXJhY3kiXQphY2MqMTAwCgpwcmVkX3Byb2JzIDwtIGFzLm51bWVyaWMocHJlZGljdChtLmN0cmVlLCBuZXdkYXRhID0gdGVzdC5kYXRhLCB0eXBlID0gInJlc3BvbnNlIikpCmJpbmFyeV9vdXRjb21lIDwtIGFzLm51bWVyaWModGVzdC5kYXRhJFBvdGFiaWxpdHkgPT0gIlBvdGFibGUiKQojIFJPQyBjdXJ2ZQpyb2NfY3VydmUgPC0gcm9jKGJpbmFyeV9vdXRjb21lLCBwcmVkX3Byb2JzKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCmBgYAoKU3BsaXR0aW5nIHRoZSBkYXRhIHNldCBpbnRvIHR3byBzdWJzZXRzOiBUcmFpbmluZyg5MCUpIGFuZCBUZXN0aW5nKDEwJSk6CmBgYHtyfQpzZXQuc2VlZCgxOTU4KQppbmQgPC0gc2FtcGxlKDIsIG5yb3cod3ApLCByZXBsYWNlID0gVFJVRSwgcHJvYiA9IGMoMC45LCAwLjEpKQp0cmFpbi5kYXRhIDwtIHdwW2luZCA9PSAxLCBdCnRlc3QuZGF0YSA8LSB3cFtpbmQgPT0gMiwgXQp0cmFpbi5kYXRhJFBvdGFiaWxpdHkgPC0gYXMuZmFjdG9yKHRyYWluLmRhdGEkUG90YWJpbGl0eSkKCm15Rm9ybXVsYSA8LSBQb3RhYmlsaXR5IH4gcGgrSGFyZG5lc3MrU29saWRzK0NobG9yYW1pbmVzK1N1bGZhdGUrQ29uZHVjdGl2aXR5K09yZ2FuaWNfY2FyYm9uK1RyaWhhbG9tZXRoYW5lcytUdXJiaWRpdHkKI215Rm9ybXVsYSA8LSBQb3RhYmlsaXR5IH4gcGgrSGFyZG5lc3MrU29saWRzK0NobG9yYW1pbmVzK1N1bGZhdGUKCgptLmN0cmVlIDwtIGN0cmVlKG15Rm9ybXVsYSwgZGF0YSA9IHRyYWluLmRhdGEpCnRhYmxlKHByZWRpY3QobS5jdHJlZSksIHRyYWluLmRhdGEkUG90YWJpbGl0eSkKCnByaW50KG0uY3RyZWUpCnBsb3QobS5jdHJlZSwgdHlwZT0ic2ltcGxlIikKCnRlc3RQcmVkIDwtIHByZWRpY3QobS5jdHJlZSwgbmV3ZGF0YSA9IHRlc3QuZGF0YSkKcmVzdWx0PC10YWJsZSh0ZXN0UHJlZCwgdGVzdC5kYXRhJFBvdGFiaWxpdHkpCgoKY29fcmVzdWx0IDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHQpCnByaW50KGNvX3Jlc3VsdCkKYXMubWF0cml4KGNvX3Jlc3VsdCwgd2hhdCA9ICJjbGFzc2VzIikKYWNjIDwtIGNvX3Jlc3VsdCRvdmVyYWxsWyJBY2N1cmFjeSJdCmFjYyoxMDAKCnByZWRfcHJvYnMgPC0gYXMubnVtZXJpYyhwcmVkaWN0KG0uY3RyZWUsIG5ld2RhdGEgPSB0ZXN0LmRhdGEsIHR5cGUgPSAicmVzcG9uc2UiKSkKYmluYXJ5X291dGNvbWUgPC0gYXMubnVtZXJpYyh0ZXN0LmRhdGEkUG90YWJpbGl0eSA9PSAiUG90YWJsZSIpCiMgUk9DIGN1cnZlCnJvY19jdXJ2ZSA8LSByb2MoYmluYXJ5X291dGNvbWUsIHByZWRfcHJvYnMpCnBsb3Qocm9jX2N1cnZlLCBtYWluID0gIlJPQyBDdXJ2ZSIsIGNvbCA9ICJibHVlIiwgbHdkID0gMikKYWJsaW5lKGEgPSAwLCBiID0gMSwgY29sID0gImdyYXkiLCBsdHkgPSAyKQojIFByaW50IEFVQwpjYXQoIkFVQzoiLCBhdWMocm9jX2N1cnZlKSwgIlxuIikKYGBgCgojIyMgR2FpbiByYXRpbyAoQzQuNSkKYSBkZWNpc2lvbiB0cmVlLWJhc2VkIGNsYXNzaWZpZXIsIGlzIHV0aWxpemVkIGZvciBtb2RlbCB0cmFpbmluZyBhbmQgZXZhbHVhdGlvbi4gVGhlIGRhdGFzZXQgdW5kZXJnb2VzIGNyb3NzLXZhbGlkYXRpb24gd2l0aCBkaWZmZXJlbnQgZm9sZCBzZXR0aW5ncyAoMyBmb2xkcywgNSBmb2xkcywgYW5kIDEwIGZvbGRzKS4gRm9yIGVhY2ggZm9sZCBjb25maWd1cmF0aW9uLCBhIEo0OCBtb2RlbCBpcyB0cmFpbmVkLCBhbmQgaXRzIHByZWRpY3RpdmUgcGVyZm9ybWFuY2UgaXMgYXNzZXNzZWQgdXNpbmcgUmVjZWl2ZXIgT3BlcmF0aW5nIENoYXJhY3RlcmlzdGljIChST0MpIGN1cnZlcy4gVGhlIEFyZWEgVW5kZXIgdGhlIEN1cnZlIGlzIGNhbGN1bGF0ZWQgZm9yIGVhY2ggUk9DIGN1cnZlLCBwcm92aWRpbmcgYSBxdWFudGl0YXRpdmUgbWVhc3VyZSBvZiB0aGUgbW9kZWwncyBhYmlsaXR5IHRvIHByZWRpY3Qgd2F0ZXIgcG90YWJpbGl0eS4gTm90YWJseSwgdGhlIHZpc3VhbCBpbnNwZWN0aW9uIG9mIHRoZSBST0MgY3VydmVzIGluZGljYXRlcyB0aGF0IHRoZSBtb2RlbCB0cmFpbmVkIHdpdGggMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uIGV4aGliaXRzIHRoZSBoaWdoZXN0IGRpc2NyaW1pbmF0aXZlIHBlcmZvcm1hbmNlLiBUaGlzIGNvbXBhcmF0aXZlIGFuYWx5c2lzIGFjcm9zcyB2YXJpb3VzIGNyb3NzLXZhbGlkYXRpb24gc2NlbmFyaW9zIG9mZmVycyB2YWx1YWJsZSBpbnNpZ2h0cyBpbnRvIHRoZSByb2J1c3RuZXNzIGFuZCBnZW5lcmFsaXphdGlvbsKgY2FwYWJpbGl0eS4KCgpgYGB7cn0KIyAzIGZvbGRzCnNldC5zZWVkKDE5NTgpCnRyYWluIDwtIGNyZWF0ZUZvbGRzKHdwJFBvdGFiaWxpdHksIGs9MykKQzQ1Rml0IDwtIHRyYWluKFBvdGFiaWxpdHkgfiAuLG1ldGhvZCA9ICJKNDgiLGRhdGEgPSB3cCwKICAgICAgICAgICAgICAgIHRyQ29udHJvbCA9IHRyYWluQ29udHJvbCgKICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJjdiIsCiAgICAgICAgICAgICAgICBpbmRleCA9IHRyYWluLAogICAgICAgICAgICAgICAgc2F2ZVByZWRpY3Rpb25zID0gVFJVRSkpCgpDNDVGaXQKCkM0NUZpdCRmaW5hbE1vZGVsCgpwcmVkX3Byb2JzIDwtIHByZWRpY3QoQzQ1Rml0LCBuZXdkYXRhID0gd3AsIHR5cGUgPSAicHJvYiIpWywgIlBvdGFibGUiXQpiaW5hcnlfb3V0Y29tZSA8LSBhcy5udW1lcmljKHdwJFBvdGFiaWxpdHkgPT0gIlBvdGFibGUiKQojIFJPQyBjdXJ2ZQpyb2NfY3VydmUgPC0gcm9jKGJpbmFyeV9vdXRjb21lLCBwcmVkX3Byb2JzKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCmBgYAoKYGBge3J9CiMgNSBmb2xkcwpzZXQuc2VlZCgxOTU4KQp0cmFpbiA8LSBjcmVhdGVGb2xkcyh3cCRQb3RhYmlsaXR5LCBrPTUpCkM0NUZpdCA8LSB0cmFpbihQb3RhYmlsaXR5IH4uLCBtZXRob2Q9Iko0OCIsIGRhdGE9d3AsCiAgICAgICAgICAgICAgICB0ckNvbnRyb2wgPSB0cmFpbkNvbnRyb2woCiAgICAgICAgICAgICAgICBtZXRob2QgPSJjdiIsIAogICAgICAgICAgICAgICAgaW5kZXggPSB0cmFpbiwKICAgICAgICAgICAgICAgIHNhdmVQcmVkaWN0aW9ucyA9IFRSVUUpKQoKQzQ1Rml0CgpDNDVGaXQkZmluYWxNb2RlbAoKcHJlZF9wcm9icyA8LSBwcmVkaWN0KEM0NUZpdCwgbmV3ZGF0YSA9IHdwLCB0eXBlID0gInByb2IiKVssICJQb3RhYmxlIl0KYmluYXJ5X291dGNvbWUgPC0gYXMubnVtZXJpYyh3cCRQb3RhYmlsaXR5ID09ICJQb3RhYmxlIikKIyBST0MgY3VydmUKcm9jX2N1cnZlIDwtIHJvYyhiaW5hcnlfb3V0Y29tZSwgcHJlZF9wcm9icykKcGxvdChyb2NfY3VydmUsIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gImJsdWUiLCBsd2QgPSAyKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIpCiMgUHJpbnQgQVVDCmNhdCgiQVVDOiIsIGF1Yyhyb2NfY3VydmUpLCAiXG4iKQoKYGBgCgpgYGB7cn0KIyAxMCBmb2xkcwpzZXQuc2VlZCgxOTU4KQp0cmFpbiA8LSBjcmVhdGVGb2xkcyh3cCRQb3RhYmlsaXR5LCBrPTEwKQpDNDVGaXQgPC0gdHJhaW4oUG90YWJpbGl0eSB+LiwgbWV0aG9kPSJKNDgiLCBkYXRhPXdwLAogICAgICAgICAgICAgICAgdHJDb250cm9sID0gdHJhaW5Db250cm9sKAogICAgICAgICAgICAgICAgICBtZXRob2Q9ImN2IiwgaW5kZXhPdXQ9dHJhaW4pKQoKQzQ1Rml0CgpDNDVGaXQkZmluYWxNb2RlbAoKcHJlZF9wcm9icyA8LSBwcmVkaWN0KEM0NUZpdCwgbmV3ZGF0YSA9IHdwLCB0eXBlID0gInByb2IiKVssICJQb3RhYmxlIl0KYmluYXJ5X291dGNvbWUgPC0gYXMubnVtZXJpYyh3cCRQb3RhYmlsaXR5ID09ICJQb3RhYmxlIikKIyBST0MgY3VydmUKcm9jX2N1cnZlIDwtIHJvYyhiaW5hcnlfb3V0Y29tZSwgcHJlZF9wcm9icykKcGxvdChyb2NfY3VydmUsIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gImJsdWUiLCBsd2QgPSAyKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIpCiMgUHJpbnQgQVVDCmNhdCgiQVVDOiIsIGF1Yyhyb2NfY3VydmUpLCAiXG4iKQoKYGBgCgpDNS4wIG5ld2VyIHZlcnNpb24gb2YgQzQuNQpTcGxpdHRpbmcgdGhlIGRhdGEgc2V0IGludG8gdHdvIHN1YnNldHM6IFRyYWluaW5nKDcwJSkgYW5kIFRlc3RpbmcoMzAlKToKYGBge3J9CnNldC5zZWVkKDE5NTgpCnRyYWluLmluZGljZXMgPC0gc2FtcGxlKDIsIG5yb3cod2F0ZXJfcG90YWJpbGl0eSksIHJlcGxhY2U9VFJVRSwgcHJvYj1jKDAuNywgMC4zKSkKdy50cmFpbiA8LSB3YXRlcl9wb3RhYmlsaXR5W3RyYWluLmluZGljZXMgPT0gMSwgXQp3LnRlc3QgPC0gd2F0ZXJfcG90YWJpbGl0eVt0cmFpbi5pbmRpY2VzID09IDIsIF0Kdy50cmFpbiRQb3RhYmlsaXR5IDwtIGFzLmZhY3Rvcih3LnRyYWluJFBvdGFiaWxpdHkpCgptb2RlbCA8LSBDNS4wKFBvdGFiaWxpdHkgfi4sIGRhdGE9dy50cmFpbikKCnJlc3VsdHMgPC0gcHJlZGljdChvYmplY3Q9bW9kZWwsIG5ld2RhdGE9dy50ZXN0LCB0eXBlPSJjbGFzcyIpCgp0YWJsZShyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKCnBsb3QobW9kZWwpCgpyIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKYWNjIDwtIHIkb3ZlcmFsbFsiQWNjdXJhY3kiXSoxMDAKYWNjCmFzLm1hdHJpeChyLCB3aGF0ID0gImNsYXNzZXMiKQpwcmludChyKQoKCgpwcmVkX3Byb2JzIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB3LnRlc3QsIHR5cGUgPSAicHJvYiIpWywgIlBvdGFibGUiXQpiaW5hcnlfb3V0Y29tZSA8LSBhcy5udW1lcmljKHcudGVzdCRQb3RhYmlsaXR5ID09ICJQb3RhYmxlIikKIyBST0MgY3VydmUKcm9jX2N1cnZlIDwtIHJvYyhiaW5hcnlfb3V0Y29tZSwgcHJlZF9wcm9icykKcGxvdChyb2NfY3VydmUsIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gImJsdWUiLCBsd2QgPSAyKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIpCiMgUHJpbnQgQVVDCmNhdCgiQVVDOiIsIGF1Yyhyb2NfY3VydmUpLCAiXG4iKQpgYGAKClNwbGl0dGluZyB0aGUgZGF0YSBzZXQgaW50byB0d28gc3Vic2V0czogVHJhaW5pbmcoODAlKSBhbmQgVGVzdGluZygyMCUpOgpgYGB7cn0Kc2V0LnNlZWQoMTk1OCkKdHJhaW4uaW5kaWNlcyA8LSBzYW1wbGUoMiwgbnJvdyh3YXRlcl9wb3RhYmlsaXR5KSwgcmVwbGFjZT1UUlVFLCBwcm9iPWMoMC44LCAwLjIpKQp3LnRyYWluIDwtIHdhdGVyX3BvdGFiaWxpdHlbdHJhaW4uaW5kaWNlcyA9PSAxLCBdCncudGVzdCA8LSB3YXRlcl9wb3RhYmlsaXR5W3RyYWluLmluZGljZXMgPT0gMiwgXQp3LnRyYWluJFBvdGFiaWxpdHkgPC0gYXMuZmFjdG9yKHcudHJhaW4kUG90YWJpbGl0eSkKCgptb2RlbCA8LSBDNS4wKFBvdGFiaWxpdHkgfi4sIGRhdGE9dy50cmFpbikKCnJlc3VsdHMgPC0gcHJlZGljdChvYmplY3Q9bW9kZWwsIG5ld2RhdGE9dy50ZXN0LCB0eXBlPSJjbGFzcyIpCgp0YWJsZShyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKCnBsb3QobW9kZWwpCgpyIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKYWNjIDwtIHIkb3ZlcmFsbFsiQWNjdXJhY3kiXSoxMDAKYWNjCmFzLm1hdHJpeChyLCB3aGF0ID0gImNsYXNzZXMiKQpwcmludChyKQoKCnByZWRfcHJvYnMgPC0gcHJlZGljdChtb2RlbCwgbmV3ZGF0YSA9IHcudGVzdCwgdHlwZSA9ICJwcm9iIilbLCAiUG90YWJsZSJdCmJpbmFyeV9vdXRjb21lIDwtIGFzLm51bWVyaWMody50ZXN0JFBvdGFiaWxpdHkgPT0gIlBvdGFibGUiKQojIFJPQyBjdXJ2ZQpyb2NfY3VydmUgPC0gcm9jKGJpbmFyeV9vdXRjb21lLCBwcmVkX3Byb2JzKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCmBgYAoKU3BsaXR0aW5nIHRoZSBkYXRhIHNldCBpbnRvIHR3byBzdWJzZXRzOiBUcmFpbmluZyg5MCUpIGFuZCBUZXN0aW5nKDEwJSk6CmBgYHtyfQpzZXQuc2VlZCgxOTU4KQp0cmFpbi5pbmRpY2VzIDwtIHNhbXBsZSgyLCBucm93KHdhdGVyX3BvdGFiaWxpdHkpLCByZXBsYWNlPVRSVUUsIHByb2I9YygwLjksIDAuMSkpCncudHJhaW4gPC0gd2F0ZXJfcG90YWJpbGl0eVt0cmFpbi5pbmRpY2VzID09IDEsIF0Kdy50ZXN0IDwtIHdhdGVyX3BvdGFiaWxpdHlbdHJhaW4uaW5kaWNlcyA9PSAyLCBdCncudHJhaW4kUG90YWJpbGl0eSA8LSBhcy5mYWN0b3Iody50cmFpbiRQb3RhYmlsaXR5KQoKCm1vZGVsIDwtIEM1LjAoUG90YWJpbGl0eSB+LiwgZGF0YT13LnRyYWluKQoKcmVzdWx0cyA8LSBwcmVkaWN0KG9iamVjdD1tb2RlbCwgbmV3ZGF0YT13LnRlc3QsIHR5cGU9ImNsYXNzIikKCnRhYmxlKHJlc3VsdHMsIHcudGVzdCRQb3RhYmlsaXR5KQoKcGxvdChtb2RlbCkKYGBgCgoKIyMjVG8gaW1wcm92ZSB0aGUgcmVhZGFiaWxpdHkgb2YgdGhlIGRlY2lzaW9uIHRyZWUsIHdlIGRlY2lkZWQgdG8gc2FtcGxlIHRoZSBkYXRhIHVzaW5nIG9ubHkgdGhlIHBIIGFuZCBzdWxmYXRlIGF0dHJpYnV0ZXMuIFdlIHRoZW4gc3BsaXQgdGhlIGRhdGEgaW50byB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXRzIHVzaW5nIHRoZSBzYW1lIHNwbGl0IHBvaW50czoKIyMjVHJhaW5pbmcoOTAlKSBhbmQgVGVzdGluZygxMCUpLCB3aGljaCBhbGxvd2VkIGZvciBhIG1vcmUgbWFuYWdlYWJsZSBkZWNpc2lvbiB0cmVlOgpgYGB7cn0Kc2V0LnNlZWQoMTk1OCkKaW1wb3J0ZW50X2ZlYXR1cmVfc2FtcGxlIDwtIHNlbGVjdCh3YXRlcl9wb3RhYmlsaXR5LGMoMSw1LDEwKSkKdHJhaW4uaW5kaWNlcyA8LSBzYW1wbGUoMiwgbnJvdyhpbXBvcnRlbnRfZmVhdHVyZV9zYW1wbGUpLCByZXBsYWNlPVRSVUUsIHByb2I9YygwLjksIDAuMSkpCncudHJhaW4gPC0gaW1wb3J0ZW50X2ZlYXR1cmVfc2FtcGxlW3RyYWluLmluZGljZXMgPT0gMSwgXQp3LnRlc3QgPC0gaW1wb3J0ZW50X2ZlYXR1cmVfc2FtcGxlW3RyYWluLmluZGljZXMgPT0gMiwgXQp3LnRyYWluJFBvdGFiaWxpdHkgPC0gYXMuZmFjdG9yKHcudHJhaW4kUG90YWJpbGl0eSkKCgptb2RlbCA8LSBDNS4wKFBvdGFiaWxpdHkgfi4sIGRhdGE9dy50cmFpbikKCnJlc3VsdHMgPC0gcHJlZGljdChvYmplY3Q9bW9kZWwsIG5ld2RhdGE9dy50ZXN0LCB0eXBlPSJjbGFzcyIpCgp0YWJsZShyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKCnBsb3QobW9kZWwpCgpyIDwtIGNvbmZ1c2lvbk1hdHJpeChyZXN1bHRzLCB3LnRlc3QkUG90YWJpbGl0eSkKYWNjIDwtIHIkb3ZlcmFsbFsiQWNjdXJhY3kiXSoxMDAKYWNjCmFzLm1hdHJpeChyLCB3aGF0ID0gImNsYXNzZXMiKQpwcmludChyKQoKCgpwcmVkX3Byb2JzIDwtIHByZWRpY3QobW9kZWwsIG5ld2RhdGEgPSB3LnRlc3QsIHR5cGUgPSAicHJvYiIpWywgIlBvdGFibGUiXQpiaW5hcnlfb3V0Y29tZSA8LSBhcy5udW1lcmljKHcudGVzdCRQb3RhYmlsaXR5ID09ICJQb3RhYmxlIikKIyBST0MgY3VydmUKcm9jX2N1cnZlIDwtIHJvYyhiaW5hcnlfb3V0Y29tZSwgcHJlZF9wcm9icykKcGxvdChyb2NfY3VydmUsIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gImJsdWUiLCBsd2QgPSAyKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIpCiMgUHJpbnQgQVVDCmNhdCgiQVVDOiIsIGF1Yyhyb2NfY3VydmUpLCAiXG4iKQpgYGAKCgoKCiMjI0dpbmkgaW5kZXggKENBUlQpCndlIGVtcGxveWVkIHRoZSBDNS4wIGFsZ29yaXRobSwgYW4gZW5oYW5jZWQgdmVyc2lvbiBvZiB0aGUgQzQuNSBkZWNpc2lvbiB0cmVlLCBmb3IgbW9kZWwgdHJhaW5pbmcgYW5kIGV2YWx1YXRpb24gYWNyb3NzIGRpZmZlcmVudCB0cmFpbmluZyBhbmQgdGVzdGluZyBzZXQgc3BsaXRzLiBUaGUgZGF0YXNldCB1bmRlcndlbnQgdGhyZWUgc2NlbmFyaW9zOiBUcmFpbmluZyg3MCUpIGFuZCBUZXN0aW5nKDMwJSksIFRyYWluaW5nKDgwJSkgYW5kIFRlc3RpbmcoMjAlKSwgYW5kIFRyYWluaW5nKDkwJSkgYW5kIFRlc3RpbmcoMTAlKS4gRm9yIGVhY2ggY2FzZSwgdGhlIEM1LjAgbW9kZWwgd2FzIHRyYWluZWQgb24gdGhlIGRlc2lnbmF0ZWQgdHJhaW5pbmcgZGF0YSwgZXZhbHVhdGVkIG9uIHRoZSB0ZXN0aW5nIGRhdGEsIGFuZCBpdHMgcGVyZm9ybWFuY2Ugd2FzIGFzc2Vzc2VkIHRocm91Z2ggYWNjdXJhY3ksIGNvbmZ1c2lvbiBtYXRyaXgsIGFuZCBST0MgY3VydmUgd2l0aCBBcmVhIFVuZGVyIHRoZSBDdXJ2ZSAoQVVDKS4KClVwb24gY29tcGFyYXRpdmUgYW5hbHlzaXMsIGl0IHdhcyBvYnNlcnZlZCB0aGF0IHRoZSBtb2RlbCB0cmFpbmVkIHdpdGggYSBsYXJnZXIgcHJvcG9ydGlvbiBvZiBkYXRhIChUcmFpbmluZyA5MCUsIFRlc3RpbmcgMTAlKSBkZW1vbnN0cmF0ZWQgc3VwZXJpb3IgcGVyZm9ybWFuY2UsIGFjaGlldmluZyBoaWdoZXIgYWNjdXJhY3kgYW5kIGEgbW9yZSBkaXNjcmltaW5hdGl2ZSBST0MgY3VydmUuIFRoaXMgZXhwbG9yYXRpb24gYWNyb3NzIGRpZmZlcmVudCB0cmFpbmluZyBhbmQgdGVzdGluZyBzcGxpdHMgcHJvdmlkZXMgdmFsdWFibGUgaW5zaWdodHMgaW50byB0aGUgcm9idXN0bmVzcyBhbmQgZ2VuZXJhbGl6YXRpb24gY2FwYWJpbGl0eSBvZiB0aGUgQzUuMCBkZWNpc2lvbiB0cmVlIGFsZ29yaXRobSBmb3IgcHJlZGljdGluZyB3YXRlcsKgcG90YWJpbGl0eS4KClNwbGl0dGluZyB0aGUgZGF0YSBzZXQgaW50byB0d28gc3Vic2V0czogVHJhaW5pbmcoNzAlKSBhbmQgVGVzdGluZygzMCUpOgpgYGB7cn0Kc2V0LnNlZWQoMTk1OCkKdHJhaW4gPSBzYW1wbGUoMiwgbnJvdyh3cCksIHJlcGxhY2U9VFJVRSwgcHJvYj1jKDAuNywgMC4zKSkKd3AudHJhaW49d3BbdHJhaW4gPT0gMSxdCndwLnRlc3Q9d3BbdHJhaW4gPT0gMixdCgoKCmZpdC50cmVlID0gcnBhcnQoUG90YWJpbGl0eSB+IC4sIGRhdGE9d3AsIG1ldGhvZCA9ICJjbGFzcyIsIGNwPTAuMDA4KQpmaXQudHJlZQoKcnBhcnQucGxvdChmaXQudHJlZSkKCmZpdC50cmVlJHZhcmlhYmxlLmltcG9ydGFuY2UKCnByZWQudHJlZSA9IHByZWRpY3QoZml0LnRyZWUsIHdwLnRlc3QsIHR5cGUgPSAiY2xhc3MiKQpyZSA8LSB0YWJsZShwcmVkLnRyZWUsIHdwLnRlc3QkUG90YWJpbGl0eSkKCmNvX3JlIDwtIGNvbmZ1c2lvbk1hdHJpeChyZSkKcHJpbnQoY29fcmUpCmFzLm1hdHJpeChjb19yZSwgd2hhdCA9ICJjbGFzc2VzIikKYWNjIDwtIGNvX3JlJG92ZXJhbGxbIkFjY3VyYWN5Il0KYWNjKjEwMAoKcGxvdGNwKGZpdC50cmVlKQpwcmludGNwKGZpdC50cmVlKQoKIyBFeHBsaWNpdGx5IHJlcXVlc3QgdGhlIGxvd2VzdCBjcCB2YWx1ZQpmaXQudHJlZSRjcHRhYmxlW3doaWNoLm1pbihmaXQudHJlZSRjcHRhYmxlWywieGVycm9yIl0pLCJDUCJdCgpiZXN0Y3AgPC1maXQudHJlZSRjcHRhYmxlW3doaWNoLm1pbihmaXQudHJlZSRjcHRhYmxlWywieGVycm9yIl0pLCJDUCJdCnBydW5lZC50cmVlIDwtIHBydW5lKGZpdC50cmVlLCBjcCA9IGJlc3RjcCkKcnBhcnQucGxvdChwcnVuZWQudHJlZSkKCnByZWQucHJ1bmUgPSBwcmVkaWN0KHBydW5lZC50cmVlLCB3cC50ZXN0LCB0eXBlPSJjbGFzcyIpCgpyZSA8LSB0YWJsZShwcmVkLnBydW5lLCB3cC50ZXN0JFBvdGFiaWxpdHkpCgpjb19yZSA8LSBjb25mdXNpb25NYXRyaXgocmUpCnByaW50KGNvX3JlKQphcy5tYXRyaXgoY29fcmUsIHdoYXQgPSAiY2xhc3NlcyIpCmFjYyA8LSBjb19yZSRvdmVyYWxsWyJBY2N1cmFjeSJdCmFjYyoxMDAKCgoKcHJlZC50cmVlX3JhdyA8LSBwcmVkaWN0KGZpdC50cmVlLCB3cC50ZXN0KQojIENvbnZlcnQgdG8gcHJvYmFiaWxpdGllcwpwcmVkLnRyZWVfcHJvYnMgPC0gZXhwKHByZWQudHJlZV9yYXcpIC8gKDEgKyBleHAocHJlZC50cmVlX3JhdykpCiMgRXh0cmFjdCBwcm9iYWJpbGl0aWVzIGZvciB0aGUgIlBvdGFibGUiIGNsYXNzCnJvY19jdXJ2ZSA8LSByb2MoaWZlbHNlKHdwLnRlc3QkUG90YWJpbGl0eSA9PSAiUG90YWJsZSIsIDEsIDApLCBwcmVkLnRyZWVfcHJvYnNbLCAiUG90YWJsZSJdKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCgoKYGBgCgpTcGxpdHRpbmcgdGhlIGRhdGEgc2V0IGludG8gdHdvIHN1YnNldHM6IFRyYWluaW5nKDgwJSkgYW5kIFRlc3RpbmcoMjAlKToKYGBge3J9CnNldC5zZWVkKDE5NTgpCnRyYWluID0gc2FtcGxlKDIsIG5yb3cod3ApLCByZXBsYWNlPVRSVUUsIHByb2I9YygwLjgsIDAuMikpCndwLnRyYWluPXdwW3RyYWluID09IDEsXQp3cC50ZXN0PXdwW3RyYWluID09IDIsXQoKCgpmaXQudHJlZSA9IHJwYXJ0KFBvdGFiaWxpdHkgfiAuLCBkYXRhPXdwLnRyYWluLCBtZXRob2QgPSAiY2xhc3MiLCBjcD0wLjAwOCkKZml0LnRyZWUKCnJwYXJ0LnBsb3QoZml0LnRyZWUpCgpmaXQudHJlZSR2YXJpYWJsZS5pbXBvcnRhbmNlCgpwcmVkLnRyZWUgPSBwcmVkaWN0KGZpdC50cmVlLCB3cC50ZXN0LCB0eXBlID0gImNsYXNzIikKcmUgPC0gdGFibGUocHJlZC50cmVlLCB3cC50ZXN0JFBvdGFiaWxpdHkpCgpjb19yZSA8LSBjb25mdXNpb25NYXRyaXgocmUpCnByaW50KGNvX3JlKQphcy5tYXRyaXgoY29fcmUsIHdoYXQgPSAiY2xhc3NlcyIpCmFjYyA8LSBjb19yZSRvdmVyYWxsWyJBY2N1cmFjeSJdCmFjYyoxMDAKCnBsb3RjcChmaXQudHJlZSkKcHJpbnRjcChmaXQudHJlZSkKCiMgRXhwbGljaXRseSByZXF1ZXN0IHRoZSBsb3dlc3QgY3AgdmFsdWUKZml0LnRyZWUkY3B0YWJsZVt3aGljaC5taW4oZml0LnRyZWUkY3B0YWJsZVssInhlcnJvciJdKSwiQ1AiXQoKYmVzdGNwIDwtZml0LnRyZWUkY3B0YWJsZVt3aGljaC5taW4oZml0LnRyZWUkY3B0YWJsZVssInhlcnJvciJdKSwiQ1AiXQpwcnVuZWQudHJlZSA8LSBwcnVuZShmaXQudHJlZSwgY3AgPSBiZXN0Y3ApCnJwYXJ0LnBsb3QocHJ1bmVkLnRyZWUpCgpwcmVkLnBydW5lID0gcHJlZGljdChwcnVuZWQudHJlZSwgd3AudGVzdCwgdHlwZT0iY2xhc3MiKQoKcmUgPC0gdGFibGUocHJlZC5wcnVuZSwgd3AudGVzdCRQb3RhYmlsaXR5KQoKY29fcmUgPC0gY29uZnVzaW9uTWF0cml4KHJlKQpwcmludChjb19yZSkKYXMubWF0cml4KGNvX3JlLCB3aGF0ID0gImNsYXNzZXMiKQphY2MgPC0gY29fcmUkb3ZlcmFsbFsiQWNjdXJhY3kiXQphY2MqMTAwCgoKcHJlZC50cmVlX3JhdyA8LSBwcmVkaWN0KGZpdC50cmVlLCB3cC50ZXN0KQpwcmVkLnRyZWVfcHJvYnMgPC0gZXhwKHByZWQudHJlZV9yYXcpIC8gKDEgKyBleHAocHJlZC50cmVlX3JhdykpCnJvY19jdXJ2ZSA8LSByb2MoaWZlbHNlKHdwLnRlc3QkUG90YWJpbGl0eSA9PSAiUG90YWJsZSIsIDEsIDApLCBwcmVkLnRyZWVfcHJvYnNbLCAiUG90YWJsZSJdKQpwbG90KHJvY19jdXJ2ZSwgbWFpbiA9ICJST0MgQ3VydmUiLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpCmFibGluZShhID0gMCwgYiA9IDEsIGNvbCA9ICJncmF5IiwgbHR5ID0gMikKIyBQcmludCBBVUMKY2F0KCJBVUM6IiwgYXVjKHJvY19jdXJ2ZSksICJcbiIpCgoKYGBgCgpTcGxpdHRpbmcgdGhlIGRhdGEgc2V0IGludG8gdHdvIHN1YnNldHM6IFRyYWluaW5nKDkwJSkgYW5kIFRlc3RpbmcoMTAlKToKYGBge3J9CnNldC5zZWVkKDE5NTgpCnRyYWluID0gc2FtcGxlKDIsIG5yb3cod3ApLCByZXBsYWNlPVRSVUUsIHByb2I9YygwLjksIDAuMSkpCndwLnRyYWluPXdwW3RyYWluID09IDEsXQp3cC50ZXN0PXdwW3RyYWluID09IDIsXQoKCgpmaXQudHJlZSA9IHJwYXJ0KFBvdGFiaWxpdHkgfiAuLCBkYXRhPXdwLnRyYWluLCBtZXRob2QgPSAiY2xhc3MiLCBjcD0wLjAwOCkKZml0LnRyZWUKCnJwYXJ0LnBsb3QoZml0LnRyZWUpCgpmaXQudHJlZSR2YXJpYWJsZS5pbXBvcnRhbmNlCgpwcmVkLnRyZWUgPSBwcmVkaWN0KGZpdC50cmVlLCB3cC50ZXN0LCB0eXBlID0gImNsYXNzIikKcmUgPC0gdGFibGUocHJlZC50cmVlLCB3cC50ZXN0JFBvdGFiaWxpdHkpCgpjb19yZSA8LSBjb25mdXNpb25NYXRyaXgocmUpCnByaW50KGNvX3JlKQphcy5tYXRyaXgoY29fcmUsIHdoYXQgPSAiY2xhc3NlcyIpCmFjYyA8LSBjb19yZSRvdmVyYWxsWyJBY2N1cmFjeSJdCmFjYyoxMDAKCnBsb3RjcChmaXQudHJlZSkKcHJpbnRjcChmaXQudHJlZSkKCiMgRXhwbGljaXRseSByZXF1ZXN0IHRoZSBsb3dlc3QgY3AgdmFsdWUKZml0LnRyZWUkY3B0YWJsZVt3aGljaC5taW4oZml0LnRyZWUkY3B0YWJsZVssInhlcnJvciJdKSwiQ1AiXQoKYmVzdGNwIDwtZml0LnRyZWUkY3B0YWJsZVt3aGljaC5taW4oZml0LnRyZWUkY3B0YWJsZVssInhlcnJvciJdKSwiQ1AiXQpwcnVuZWQudHJlZSA8LSBwcnVuZShmaXQudHJlZSwgY3AgPSBiZXN0Y3ApCnJwYXJ0LnBsb3QocHJ1bmVkLnRyZWUpCgpwcmVkLnBydW5lID0gcHJlZGljdChwcnVuZWQudHJlZSwgd3AudGVzdCwgdHlwZT0iY2xhc3MiKQoKcmUgPC0gdGFibGUocHJlZC5wcnVuZSwgd3AudGVzdCRQb3RhYmlsaXR5KQoKY29fcmUgPC0gY29uZnVzaW9uTWF0cml4KHJlKQpwcmludChjb19yZSkKYXMubWF0cml4KGNvX3JlLCB3aGF0ID0gImNsYXNzZXMiKQphY2MgPC0gY29fcmUkb3ZlcmFsbFsiQWNjdXJhY3kiXQphY2MqMTAwCgoKCnByZWQudHJlZV9yYXcgPC0gcHJlZGljdChmaXQudHJlZSwgd3AudGVzdCkKcHJlZC50cmVlX3Byb2JzIDwtIGV4cChwcmVkLnRyZWVfcmF3KSAvICgxICsgZXhwKHByZWQudHJlZV9yYXcpKQpyb2NfY3VydmUgPC0gcm9jKGlmZWxzZSh3cC50ZXN0JFBvdGFiaWxpdHkgPT0gIlBvdGFibGUiLCAxLCAwKSwgcHJlZC50cmVlX3Byb2JzWywgIlBvdGFibGUiXSkKcGxvdChyb2NfY3VydmUsIG1haW4gPSAiUk9DIEN1cnZlIiwgY29sID0gImJsdWUiLCBsd2QgPSAyKQphYmxpbmUoYSA9IDAsIGIgPSAxLCBjb2wgPSAiZ3JheSIsIGx0eSA9IDIpCiMgUHJpbnQgQVVDCmNhdCgiQVVDOiIsIGF1Yyhyb2NfY3VydmUpLCAiXG4iKQpgYGAKIyMjIENvbXBhcmlzb24gQ3JpdGVyaWE6Cgp8ICAgICAgICAgICAgfEluZm9ybWF0aW9uIEdhaW46ICAgICAgICAgICAgICAgfEdhaW4gUmF0aW86ICAgICAgICAgICAgICAgICAgICAgfCBHaW5pIGluZGV4OiAgICAgICAgICAgICAgICAgICAgICB8CnwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBBY2N1cmFjeSAgIHwgMC41ODIwNjExICAgICAgICAgICAgICAgICAgICAgIHwgMC45Njg2NzgxICAgICAgICAgICAgICAgICAgICAgIHwgMC41OTM1MTE1ICAgICAgICAgICAgICAgICAgICAgICAgfAp8IHByZWNpc2lvbiAgfCAwLjU4NTQ2MTY5ICAgICAgICAgICAgICAgICAgICAgfCAwLjAwNTQxNzEzMiAgICAgICAgICAgICAgICAgICAgfCAwLjYwMDQzMjAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgCnwgc2Vuc2l0aXZpdHl8IDAuOTczODU2MjEgICAgICAgICAgICAgICAgICAgICB8IDAuOTMzNDc0MSAgICAgICAgICAgICAgICAgICAgICB8IDAuOTA4NDk2NyAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgCnwgc3BlY2lmaWNpdHl8IDAuMDMyMTEwMDkgICAgICAgICAgICAgICAgICAgICB8IDAuODgwNjc3ICAgICAgICAgICAgICAgICAgICAgICB8IDAuMTUxMzc2MSAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApBcyBzaG93biBpbiB0aGUgY29tcGFyaXNvbiB0aGUgYmVzdCB0ZWNobmlxdWUgdG8gY2hvb3NlIGlzIEdhaW4gUmFpbyBEdWUgdG8gdGhlIGhpZ2ggYWNjdXJhY3kgCgoKYGBge3J9ClZpZXcod2F0ZXJfcG90YWJpbGl0eSkKZGF0YSgid2F0ZXJfcG90YWJpbGl0eSIpCnN1bW1hcnkod2F0ZXJfcG90YWJpbGl0eSkKc3RyKHdhdGVyX3BvdGFiaWxpdHkpCmBgYAoKIyMgQ2x1c3RlcmluZwoKIyBkZXRlcm1pbmUgYW5kIHZpc3VhbGl6ZSBvcHRpbWFsIG51bWJlciBvZiBjbHVzdGVyczoKCndlIHdpbGwgdXNlIGZvdXIgZGlmZmVyZW50IHNpemVzIG9mIGsgZm9yIGNsdXN0ZXJpbmcgYW5kIHRoZW4gc2VlIHdoYXQgcGVyZm9ybXMgYmVzdCBiZXR3ZWVuIHRoZW0uCgojIyMgU2NhbGUgZGF0YSBmaXJzdDoKCkNvbmZpcm0gdGhhdCBhbGwgdGhlIGNvbHVtbnMgeW91IGFyZSB0cnlpbmcgdG8gc2NhbGUgYXJlIGluZGVlZCBudW1lcmljLiBZb3UgY2FuIHVzZSBzYXBwbHkoKSB0byBjaGVjayBhbmQgY29lcmNlIHRoZW0gdG8gbnVtZXJpYyBpZiBuZWNlc3NhcnkuCgpzaW5lYyBhbGwgY291bG1lIGFyZSBudW1lcmljIHdlIHdsbCBzY2FsZSBhbGwgb2YgdGhlbSBleHBldCBjbGFzcyBsYWJlbCBhbmQgd2Ugc2F2ZWQgaXQgaW4gZGF0YXNldCBjYWxsZWQgQ2x1c3RlciBhbmQgd2UgdXNlZCBpdCBpbiBDbHVzdHJpbmcKCmBgYHtyfQp3YXRlcl9wb3RhYmlsaXR5PC0gc2FwcGx5KHdhdGVyX3BvdGFiaWxpdHksIGFzLm51bWVyaWMpCgpkYXRhX2Zvcl9jbHVzdGVyIDwtIHNjYWxlKHdhdGVyX3BvdGFiaWxpdHlbLCAhY29sbmFtZXMod2F0ZXJfcG90YWJpbGl0eSkgJWluJSAiUG90YWJpbGl0eSJdKQojd2UgdXNlICFjb2xuYW1lcyh3YXRlcl9wb3RhYmlsaXR5KSAlaW4lICJQb3RhYmlsaXR5IiB0byBleGNsdWRlIHRoZSAiUG90YWJpbGl0eSIgY29sdW1uClZpZXcoZGF0YV9mb3JfY2x1c3RlcikKYGBgCgojIyBDbHVzdHJpbmcxCgojIyMgSy1tZWFucwoKYGBge3J9CiMgMy0gcnVuIGstbWVhbnMgY2x1c3RlcmluZyB0byBmaW5kIDIgY2x1c3RlcnMKI3NldCBhIHNlZWQgZm9yIHJhbmRvbSBudW1iZXIgZ2VuZXJhdGlvbiAgdG8gbWFrZSB0aGUgcmVzdWx0cyByZXByb2R1Y2libGUKc2V0LnNlZWQoODk1MykKa21lYW5zLnJlc3VsdCA8LSBrbWVhbnMoZGF0YV9mb3JfY2x1c3RlciwyKQojIHByaW50IHRoZSBjbHVzdGVybmcgcmVzdWx0CmttZWFucy5yZXN1bHQKYGBgCgojIyMgdmlzdWFsaXplIGNsdXN0ZXJpbmcKCmBgYHtyfQojIHZpc3VhbGl6ZSBjbHVzdGVyaW5nICgyIGNsdXN0ZXJzKQppbnN0YWxsLnBhY2thZ2VzKCJmYWN0b2V4dHJhIikKbGlicmFyeShmYWN0b2V4dHJhKQpmdml6X2NsdXN0ZXIoa21lYW5zLnJlc3VsdCwgZGF0YSA9IGRhdGFfZm9yX2NsdXN0ZXIpCmBgYAoKIyMjIGhpZXJjcmNoaWNhbCBjbHVzdGVyaW5nCgp3ZSB0b29rIDUwIHNhbXBsZSB0byBtYWtlIGl0IG1vcmUgdW5kZXJzdGFiYWxlCgpgYGB7cn0KIyBkcmF3IGEgc2FtcGxlIG9mIDUwIHJlY29yZHMgZnJvbSB0aGUgZGF0YSwgc28gdGhhdCB0aGUgY2x1c3RlcmluZyBwbG90IHdpbGwgbm90IGJlIG92ZXIgY3Jvd2RlZCBhbmQgZWFzeSB0byB1bmRyZXN0YW5kIAppZHg8LXNhbXBsZSgxOmRpbShkYXRhX2Zvcl9jbHVzdGVyKVsxXSwgNTApCnNhbXBsZV9jMTwtZGF0YV9mb3JfY2x1c3RlcltpZHgsIF0KCiMjIGhpZXJjcmNoaWNhbCBjbHVzdGVyaW5nCmhjLmN1dDwtIGhjdXQoc2FtcGxlX2MxLCBrID0gMiwgaGNfbWV0aG9kPSAiY29tcGxldGUiKQpgYGAKCiMjIyBWaXN1YWxpemUgZGVuZHJvZ3JhbSBhbmQgc2FtcGxlIENsdXN0ZXJpbmcKCmRlbmRyb2dyYW0gaXMgYSB0cmVlIGRpYWdyYW0gdGhhdCBkaXNwbGF5cyB0aGUgYXJyYW5nZW1lbnQgb2YgZGF0YSBwb2ludHMgaW4gYSBoaWVyYXJjaGljYWwgb3JkZXIgYmFzZWQgb24gdGhlaXIgc2ltaWxhcml0eSBvciBkaXNzaW1pbGFyaXR5LgoKYGBge3J9CiMgVmlzdWFsaXplIGRlbmRyb2dyYW0KZnZpel9kZW5kKGhjLmN1dCxyZWN0PSBUUlVFKQojIFZpc3VhbGl6ZSBjbHVzdGVyCmZ2aXpfY2x1c3RlcihoYy5jdXQsIGVsbGlwc2UudHlwZT0gImNvbnZleCIpCmBgYAoKIyMjIGF2ZXJhZ2Ugc2lsaG91ZXR0ZQoKVGhpcyBtZXRob2QgY2FsY3VsYXRlcyB0aGUgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGssIGRldGVybWluaW5nIGhvdyB3ZWxsIGRhdGEgcG9pbnRzIGZpdCBpbnRvIHRoZWlyIGFzc2lnbmVkIGNsdXN0ZXJzLgoKYGBge3J9CiAjYXZlcmFnZSBzaWxob3VldHRlIGZvciBlYWNoIGNsdXN0ZXJzIAppbnN0YWxsLnBhY2thZ2VzKGNsdXN0ZXIpCmxpYnJhcnkoY2x1c3RlcikKYXZnX3NpbCA8LSBzaWxob3VldHRlKGttZWFucy5yZXN1bHQkY2x1c3RlcixkaXN0KGRhdGFfZm9yX2NsdXN0ZXIpKSAjYSBkaXNzaW1pbGFyaXR5IG9iamVjdCBpbmhlcml0aW5nIGZyb20gY2xhc3MgZGlzdCBvciBjb2VyY2libGUgdG8gb25lLiBJZiBub3Qgc3BlY2lmaWVkLCBkbWF0cml4IG11c3QgYmUuCmZ2aXpfc2lsaG91ZXR0ZShhdmdfc2lsKSNrLW1lYW5zIGNsdXN0ZXJpbmcgd2l0aCBlc3RpbWF0aW5nIGsgYW5kIGluaXRpYWxpemF0aW9ucwpgYGAKCiMjIyBCQ3ViZWQgcHJlY2lzaW9uIGFuZCByZWNhbGwKCkJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbCBhcmUgbWV0cmljcyB1c2VkIHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBjbHVzdGVyaW5nIGFsZ29yaXRobXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgY29udGV4dCBvZiBldmFsdWF0aW5nIHRoZSBxdWFsaXR5IG9mIGNsdXN0ZXJpbmcgYXNzaWdubWVudHMgZm9yIGluZGl2aWR1YWwgZGF0YSBwb2ludHMuCgpgYGB7cn0KCmNsdXN0ZXJfYXNzaWdubWVudHMgPC0gYyhrbWVhbnMucmVzdWx0JGNsdXN0ZXIpCmdyb3VuZF90cnV0aF9sYWJlbHMgPC0gYyh3YXRlcl9wb3RhYmlsaXR5KQpkYXRhIDwtIGRhdGEuZnJhbWUoY2x1c3RlciA9IGNsdXN0ZXJfYXNzaWdubWVudHMsIGxhYmVsID0gZ3JvdW5kX3RydXRoX2xhYmVscykKCiMgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbApjYWxjdWxhdGVfYmN1YmVkX21ldHJpY3MgPC0gZnVuY3Rpb24oZGF0YSkgewogIG4gPC0gbnJvdyhkYXRhKQogIHByZWNpc2lvbl9zdW0gPC0gMAogIHJlY2FsbF9zdW0gPC0gMAoKICBmb3IgKGkgaW4gMTpuKSB7CiAgICBjbHVzdGVyIDwtIGRhdGEkY2x1c3RlcltpXQogICAgbGFiZWwgPC0gZGF0YSRsYWJlbFtpXQogICAgCiMgQ291bnQgdGhlIG51bWJlciBvZiBpdGVtcyBmcm9tIHRoZSBzYW1lIGNhdGVnb3J5IHdpdGhpbiB0aGUgc2FtZSBjbHVzdGVyCnNhbWVfY2F0ZWdvcnlfc2FtZV9jbHVzdGVyIDwtIHN1bShkYXRhJGxhYmVsW2RhdGEkY2x1c3RlciA9PSBjbHVzdGVyXSA9PSBsYWJlbCkKICAgIAojIENvdW50IHRoZSB0b3RhbCBudW1iZXIgb2YgaXRlbXMgaW4gdGhlIHNhbWUgY2x1c3Rlcgp0b3RhbF9zYW1lX2NsdXN0ZXIgPC0gc3VtKGRhdGEkY2x1c3RlciA9PSBjbHVzdGVyKQogICAgCiMgQ291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyB3aXRoIHRoZSBzYW1lIGNhdGVnb3J5CnRvdGFsX3NhbWVfY2F0ZWdvcnkgPC0gc3VtKGRhdGEkbGFiZWwgPT0gbGFiZWwpCiAgICAKIyBDYWxjdWxhdGUgcHJlY2lzaW9uIGFuZCByZWNhbGwgZm9yIHRoZSBjdXJyZW50IGl0ZW0gYW5kIGFkZCB0aGVtIHRvIHRoZSBzdW1zCnByZWNpc2lvbl9zdW0gPC0gcHJlY2lzaW9uX3N1bSArIHNhbWVfY2F0ZWdvcnlfc2FtZV9jbHVzdGVyIC90b3RhbF9zYW1lX2NsdXN0ZXIKcmVjYWxsX3N1bSA8LSByZWNhbGxfc3VtICsgc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgLyB0b3RhbF9zYW1lX2NhdGVnb3J5CiAgfQoKICAjIENhbGN1bGF0ZSBhdmVyYWdlIHByZWNpc2lvbiBhbmQgcmVjYWxsCiAgcHJlY2lzaW9uIDwtIHByZWNpc2lvbl9zdW0gLyBuCiAgcmVjYWxsIDwtIHJlY2FsbF9zdW0gLyBuCgogIHJldHVybihsaXN0KHByZWNpc2lvbiA9IHByZWNpc2lvbiwgcmVjYWxsID0gcmVjYWxsKSkKfQoKIyBDYWxjdWxhdGUgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsCm1ldHJpY3MgPC0gY2FsY3VsYXRlX2JjdWJlZF9tZXRyaWNzKGRhdGEpCgojIEV4dHJhY3QgcHJlY2lzaW9uIGFuZCByZWNhbGwgZnJvbSB0aGUgbWV0cmljcwpwcmVjaXNpb24gPC0gbWV0cmljcyRwcmVjaXNpb24KcmVjYWxsIDwtIG1ldHJpY3MkcmVjYWxsCgojIFByaW50IHRoZSByZXN1bHRzCmNhdCgiQkN1YmVkIFByZWNpc2lvbjoiLCBwcmVjaXNpb24sICJcbiIpCmNhdCgiQkN1YmVkIFJlY2FsbDoiLCByZWNhbGwsICJcbiIpCgpgYGAKCiMjIENsdXN0cmluZzIKCiMjIyBLLW1lYW5zCgpydW4gay1tZWFucyBjbHVzdGVyaW5nIHRvIGZpbmQgMyBjbHVzdGVycyBzZXQgYSBzZWVkIGZvciByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24gdG8gbWFrZSB0aGUgcmVzdWx0cyByZXByb2R1Y2libGUKCmBgYHtyfQpzZXQuc2VlZCg4OTUzKQprbWVhbnMucmVzdWx0IDwtIGttZWFucyhkYXRhX2Zvcl9jbHVzdGVyLDMpCiMgcHJpbnQgdGhlIENsdXN0cmluZyByZXN1bHQKa21lYW5zLnJlc3VsdApgYGAKCiMjIyB2aXN1YWxpemUgY2x1c3RlcmluZwoKYGBge3J9CiMgdmlzdWFsaXplIGNsdXN0ZXJpbmcgKDMgY2x1c3RlcnMpCmluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmZ2aXpfY2x1c3RlcihrbWVhbnMucmVzdWx0LCBkYXRhID0gZGF0YV9mb3JfY2x1c3RlcikKYGBgCgojIyMgaGllcmNyY2hpY2FsIGNsdXN0ZXJpbmcKCmBgYHtyfQojIGRyYXcgYSBzYW1wbGUgb2YgNTAgcmVjb3JkcyBmcm9tIHRoZSBkYXRhLCBzbyB0aGF0IHRoZSBjbHVzdGVyaW5nIHBsb3Qgd2lsbCBub3QgYmUgb3ZlciBjcm93ZGVkIGFuZCBlYXN5IHRvIHVuZHJlc3RhbmQgCgppZHgyPC1zYW1wbGUoMTpkaW0oZGF0YV9mb3JfY2x1c3RlcilbMV0sIDUwKQpzYW1wbGVfYzI8LWRhdGFfZm9yX2NsdXN0ZXJbaWR4MiwgXQoKIyMgaGllcmNyY2hpY2FsIGNsdXN0ZXJpbmcKaGMyLmN1dDwtIGhjdXQoc2FtcGxlX2MyLCBrID0gMywgaGNfbWV0aG9kPSAiY29tcGxldGUiKQpgYGAKCiMjIyBWaXN1YWxpemUgZGVuZHJvZ3JhbQoKZGVuZHJvZ3JhbSBpcyBhIHRyZWUgZGlhZ3JhbSB0aGF0IGRpc3BsYXlzIHRoZSBhcnJhbmdlbWVudCBvZiBkYXRhIHBvaW50cyBpbiBhIGhpZXJhcmNoaWNhbCBvcmRlciBiYXNlZCBvbiB0aGVpciBzaW1pbGFyaXR5IG9yIGRpc3NpbWlsYXJpdHkuCgpgYGB7cn0KZnZpel9kZW5kKGhjMi5jdXQscmVjdD0gVFJVRSkKIyBWaXN1YWxpemUgY2x1c3Rlcgpmdml6X2NsdXN0ZXIoaGMyLmN1dCwgZWxsaXBzZS50eXBlPSAiY29udmV4IikKYGBgCgojIyMgYXZlcmFnZSBzaWxob3VldHRlCgpUaGlzIG1ldGhvZCBjYWxjdWxhdGVzIHRoZSBhdmVyYWdlIHNpbGhvdWV0dGUgd2lkdGggZm9yIGRpZmZlcmVudCB2YWx1ZXMgb2YgaywgZGV0ZXJtaW5pbmcgaG93IHdlbGwgZGF0YSBwb2ludHMgZml0IGludG8gdGhlaXIgYXNzaWduZWQgY2x1c3RlcnMuCgpgYGB7cn0KICNhdmVyYWdlIHNpbGhvdWV0dGUgZm9yIGVhY2ggY2x1c3RlcnMgCmluc3RhbGwucGFja2FnZXMoY2x1c3RlcikKbGlicmFyeShjbHVzdGVyKQphdmdfc2lsIDwtIHNpbGhvdWV0dGUoa21lYW5zLnJlc3VsdCRjbHVzdGVyLGRpc3QoZGF0YV9mb3JfY2x1c3RlcikpICNhIGRpc3NpbWlsYXJpdHkgb2JqZWN0IGluaGVyaXRpbmcgZnJvbSBjbGFzcyBkaXN0IG9yIGNvZXJjaWJsZSB0byBvbmUuIElmIG5vdCBzcGVjaWZpZWQsIGRtYXRyaXggbXVzdCBiZS4KZnZpel9zaWxob3VldHRlKGF2Z19zaWwpI2stbWVhbnMgY2x1c3RlcmluZyB3aXRoIGVzdGltYXRpbmcgayBhbmQgaW5pdGlhbGl6YXRpb25zCmBgYAoKIyMjIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbAoKQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsIGFyZSBtZXRyaWNzIHVzZWQgdG8gZXZhbHVhdGUgdGhlIHBlcmZvcm1hbmNlIG9mIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcywgcGFydGljdWxhcmx5IGluIHRoZSBjb250ZXh0IG9mIGV2YWx1YXRpbmcgdGhlIHF1YWxpdHkgb2YgY2x1c3RlcmluZyBhc3NpZ25tZW50cyBmb3IgaW5kaXZpZHVhbCBkYXRhIHBvaW50cy4KCmBgYHtyfQoKY2x1c3Rlcl9hc3NpZ25tZW50cyA8LSBjKGttZWFucy5yZXN1bHQkY2x1c3RlcikKZ3JvdW5kX3RydXRoX2xhYmVscyA8LSBjKHdhdGVyX3BvdGFiaWxpdHkpCmRhdGEgPC0gZGF0YS5mcmFtZShjbHVzdGVyID0gY2x1c3Rlcl9hc3NpZ25tZW50cywgbGFiZWwgPSBncm91bmRfdHJ1dGhfbGFiZWxzKQoKIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsCmNhbGN1bGF0ZV9iY3ViZWRfbWV0cmljcyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgbiA8LSBucm93KGRhdGEpCiAgcHJlY2lzaW9uX3N1bSA8LSAwCiAgcmVjYWxsX3N1bSA8LSAwCgogIGZvciAoaSBpbiAxOm4pIHsKICAgIGNsdXN0ZXIgPC0gZGF0YSRjbHVzdGVyW2ldCiAgICBsYWJlbCA8LSBkYXRhJGxhYmVsW2ldCiAgICAKIyBDb3VudCB0aGUgbnVtYmVyIG9mIGl0ZW1zIGZyb20gdGhlIHNhbWUgY2F0ZWdvcnkgd2l0aGluIHRoZSBzYW1lIGNsdXN0ZXIKc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgPC0gc3VtKGRhdGEkbGFiZWxbZGF0YSRjbHVzdGVyID09IGNsdXN0ZXJdID09IGxhYmVsKQogICAgCiMgQ291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyBpbiB0aGUgc2FtZSBjbHVzdGVyCnRvdGFsX3NhbWVfY2x1c3RlciA8LSBzdW0oZGF0YSRjbHVzdGVyID09IGNsdXN0ZXIpCiAgICAKIyBDb3VudCB0aGUgdG90YWwgbnVtYmVyIG9mIGl0ZW1zIHdpdGggdGhlIHNhbWUgY2F0ZWdvcnkKdG90YWxfc2FtZV9jYXRlZ29yeSA8LSBzdW0oZGF0YSRsYWJlbCA9PSBsYWJlbCkKICAgIAojIENhbGN1bGF0ZSBwcmVjaXNpb24gYW5kIHJlY2FsbCBmb3IgdGhlIGN1cnJlbnQgaXRlbSBhbmQgYWRkIHRoZW0gdG8gdGhlIHN1bXMKcHJlY2lzaW9uX3N1bSA8LSBwcmVjaXNpb25fc3VtICsgc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgL3RvdGFsX3NhbWVfY2x1c3RlcgpyZWNhbGxfc3VtIDwtIHJlY2FsbF9zdW0gKyBzYW1lX2NhdGVnb3J5X3NhbWVfY2x1c3RlciAvIHRvdGFsX3NhbWVfY2F0ZWdvcnkKICB9CgogICMgQ2FsY3VsYXRlIGF2ZXJhZ2UgcHJlY2lzaW9uIGFuZCByZWNhbGwKICBwcmVjaXNpb24gPC0gcHJlY2lzaW9uX3N1bSAvIG4KICByZWNhbGwgPC0gcmVjYWxsX3N1bSAvIG4KCiAgcmV0dXJuKGxpc3QocHJlY2lzaW9uID0gcHJlY2lzaW9uLCByZWNhbGwgPSByZWNhbGwpKQp9CgojIENhbGN1bGF0ZSBCQ3ViZWQgcHJlY2lzaW9uIGFuZCByZWNhbGwKbWV0cmljcyA8LSBjYWxjdWxhdGVfYmN1YmVkX21ldHJpY3MoZGF0YSkKCiMgRXh0cmFjdCBwcmVjaXNpb24gYW5kIHJlY2FsbCBmcm9tIHRoZSBtZXRyaWNzCnByZWNpc2lvbiA8LSBtZXRyaWNzJHByZWNpc2lvbgpyZWNhbGwgPC0gbWV0cmljcyRyZWNhbGwKCiMgUHJpbnQgdGhlIHJlc3VsdHMKY2F0KCJCQ3ViZWQgUHJlY2lzaW9uOiIsIHByZWNpc2lvbiwgIlxuIikKY2F0KCJCQ3ViZWQgUmVjYWxsOiIsIHJlY2FsbCwgIlxuIikKCmBgYAoKIyMgQ2x1c3RyaW5nMwoKIyMjIEstbWVhbnMKCmBgYHtyfQojIDMtIHJ1biBrLW1lYW5zIGNsdXN0ZXJpbmcgdG8gZmluZCA0IGNsdXN0ZXJzCiNzZXQgYSBzZWVkIGZvciByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24gIHRvIG1ha2UgdGhlIHJlc3VsdHMgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDg5NTMpCmttZWFucy5yZXN1bHQgPC0ga21lYW5zKGRhdGFfZm9yX2NsdXN0ZXIsNCkKIyBwcmludCB0aGUgY2x1c3RlcmluZyByZXN1bHQKa21lYW5zLnJlc3VsdApgYGAKCiMjIyB2aXN1YWxpemUgY2x1c3RlcmluZwoKYGBge3J9CiMgdmlzdWFsaXplIGNsdXN0ZXJpbmcgKDQgY2x1c3RlcnMpCmluc3RhbGwucGFja2FnZXMoImZhY3RvZXh0cmEiKQpsaWJyYXJ5KGZhY3RvZXh0cmEpCmZ2aXpfY2x1c3RlcihrbWVhbnMucmVzdWx0LCBkYXRhID0gZGF0YV9mb3JfY2x1c3RlcikKYGBgCgojIyMgaGllcmNyY2hpY2FsIGNsdXN0ZXJpbmcKCmBgYHtyfQojIGRyYXcgYSBzYW1wbGUgb2YgNTAgcmVjb3JkcyBmcm9tIHRoZSBkYXRhLCBzbyB0aGF0IHRoZSBjbHVzdGVyaW5nIHBsb3Qgd2lsbCBub3QgYmUgb3ZlciBjcm93ZGVkIGFuZCBlYXN5IHRvIHVuZHJlc3RhbmQgCmlkeDM8LXNhbXBsZSgxOmRpbShkYXRhX2Zvcl9jbHVzdGVyKVsxXSwgNTApCnNhbXBsZV9jMzwtZGF0YV9mb3JfY2x1c3RlcltpZHgzLCBdCgojIyBoaWVyY3JjaGljYWxjbHVzdGVyaW5nCmhjMy5jdXQ8LSBoY3V0KHNhbXBsZV9jMywgayA9IDQsIGhjX21ldGhvZD0gImNvbXBsZXRlIikKYGBgCgojIyMgI2RlbmRyb2dyYW0KCmRlbmRyb2dyYW0gaXMgYSB0cmVlIGRpYWdyYW0gdGhhdCBkaXNwbGF5cyB0aGUgYXJyYW5nZW1lbnQgb2YgZGF0YSBwb2ludHMgaW4gYSBoaWVyYXJjaGljYWwgb3JkZXIgYmFzZWQgb24gdGhlaXIgc2ltaWxhcml0eSBvciBkaXNzaW1pbGFyaXR5LgoKYGBge3J9CiMgVmlzdWFsaXplIGRlbmRyb2dyYW0KZnZpel9kZW5kKGhjMy5jdXQscmVjdD0gVFJVRSkKIyBWaXN1YWxpemUgY2x1c3Rlcgpmdml6X2NsdXN0ZXIoaGMzLmN1dCwgZWxsaXBzZS50eXBlPSAiY29udmV4IikKYGBgCgojIyMgI2F2ZXJhZ2Ugc2lsaG91ZXR0ZQoKVGhpcyBtZXRob2QgY2FsY3VsYXRlcyB0aGUgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGssIGRldGVybWluaW5nIGhvdyB3ZWxsIGRhdGEgcG9pbnRzIGZpdCBpbnRvIHRoZWlyIGFzc2lnbmVkIGNsdXN0ZXJzLgoKYGBge3J9CiAjYXZlcmFnZSBzaWxob3VldHRlIGZvciBlYWNoIGNsdXN0ZXJzIAppbnN0YWxsLnBhY2thZ2VzKGNsdXN0ZXIpCmxpYnJhcnkoY2x1c3RlcikKYXZnX3NpbCA8LSBzaWxob3VldHRlKGttZWFucy5yZXN1bHQkY2x1c3RlcixkaXN0KGRhdGFfZm9yX2NsdXN0ZXIpKSAjYSBkaXNzaW1pbGFyaXR5IG9iamVjdCBpbmhlcml0aW5nIGZyb20gY2xhc3MgZGlzdCBvciBjb2VyY2libGUgdG8gb25lLiBJZiBub3Qgc3BlY2lmaWVkLCBkbWF0cml4IG11c3QgYmUuCmZ2aXpfc2lsaG91ZXR0ZShhdmdfc2lsKSNrLW1lYW5zIGNsdXN0ZXJpbmcgd2l0aCBlc3RpbWF0aW5nIGsgYW5kIGluaXRpYWxpemF0aW9ucwpgYGAKCiMjIyBCQ3ViZWQgcHJlY2lzaW9uIGFuZCByZWNhbGwKCkJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbCBhcmUgbWV0cmljcyB1c2VkIHRvIGV2YWx1YXRlIHRoZSBwZXJmb3JtYW5jZSBvZiBjbHVzdGVyaW5nIGFsZ29yaXRobXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgY29udGV4dCBvZiBldmFsdWF0aW5nIHRoZSBxdWFsaXR5IG9mIGNsdXN0ZXJpbmcgYXNzaWdubWVudHMgZm9yIGluZGl2aWR1YWwgZGF0YSBwb2ludHMuCgpgYGB7cn0KCmNsdXN0ZXJfYXNzaWdubWVudHMgPC0gYyhrbWVhbnMucmVzdWx0JGNsdXN0ZXIpCmdyb3VuZF90cnV0aF9sYWJlbHMgPC0gYyh3YXRlcl9wb3RhYmlsaXR5KQpkYXRhIDwtIGRhdGEuZnJhbWUoY2x1c3RlciA9IGNsdXN0ZXJfYXNzaWdubWVudHMsIGxhYmVsID0gZ3JvdW5kX3RydXRoX2xhYmVscykKCiMgRnVuY3Rpb24gdG8gY2FsY3VsYXRlIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbApjYWxjdWxhdGVfYmN1YmVkX21ldHJpY3MgPC0gZnVuY3Rpb24oZGF0YSkgewogIG4gPC0gbnJvdyhkYXRhKQogIHByZWNpc2lvbl9zdW0gPC0gMAogIHJlY2FsbF9zdW0gPC0gMAoKICBmb3IgKGkgaW4gMTpuKSB7CiAgICBjbHVzdGVyIDwtIGRhdGEkY2x1c3RlcltpXQogICAgbGFiZWwgPC0gZGF0YSRsYWJlbFtpXQogICAgCiMgQ291bnQgdGhlIG51bWJlciBvZiBpdGVtcyBmcm9tIHRoZSBzYW1lIGNhdGVnb3J5IHdpdGhpbiB0aGUgc2FtZSBjbHVzdGVyCnNhbWVfY2F0ZWdvcnlfc2FtZV9jbHVzdGVyIDwtIHN1bShkYXRhJGxhYmVsW2RhdGEkY2x1c3RlciA9PSBjbHVzdGVyXSA9PSBsYWJlbCkKICAgIAojIENvdW50IHRoZSB0b3RhbCBudW1iZXIgb2YgaXRlbXMgaW4gdGhlIHNhbWUgY2x1c3Rlcgp0b3RhbF9zYW1lX2NsdXN0ZXIgPC0gc3VtKGRhdGEkY2x1c3RlciA9PSBjbHVzdGVyKQogICAgCiMgQ291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyB3aXRoIHRoZSBzYW1lIGNhdGVnb3J5CnRvdGFsX3NhbWVfY2F0ZWdvcnkgPC0gc3VtKGRhdGEkbGFiZWwgPT0gbGFiZWwpCiAgICAKIyBDYWxjdWxhdGUgcHJlY2lzaW9uIGFuZCByZWNhbGwgZm9yIHRoZSBjdXJyZW50IGl0ZW0gYW5kIGFkZCB0aGVtIHRvIHRoZSBzdW1zCnByZWNpc2lvbl9zdW0gPC0gcHJlY2lzaW9uX3N1bSArIHNhbWVfY2F0ZWdvcnlfc2FtZV9jbHVzdGVyIC90b3RhbF9zYW1lX2NsdXN0ZXIKcmVjYWxsX3N1bSA8LSByZWNhbGxfc3VtICsgc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgLyB0b3RhbF9zYW1lX2NhdGVnb3J5CiAgfQoKICAjIENhbGN1bGF0ZSBhdmVyYWdlIHByZWNpc2lvbiBhbmQgcmVjYWxsCiAgcHJlY2lzaW9uIDwtIHByZWNpc2lvbl9zdW0gLyBuCiAgcmVjYWxsIDwtIHJlY2FsbF9zdW0gLyBuCgogIHJldHVybihsaXN0KHByZWNpc2lvbiA9IHByZWNpc2lvbiwgcmVjYWxsID0gcmVjYWxsKSkKfQoKIyBDYWxjdWxhdGUgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsCm1ldHJpY3MgPC0gY2FsY3VsYXRlX2JjdWJlZF9tZXRyaWNzKGRhdGEpCgojIEV4dHJhY3QgcHJlY2lzaW9uIGFuZCByZWNhbGwgZnJvbSB0aGUgbWV0cmljcwpwcmVjaXNpb24gPC0gbWV0cmljcyRwcmVjaXNpb24KcmVjYWxsIDwtIG1ldHJpY3MkcmVjYWxsCgojIFByaW50IHRoZSByZXN1bHRzCmNhdCgiQkN1YmVkIFByZWNpc2lvbjoiLCBwcmVjaXNpb24sICJcbiIpCmNhdCgiQkN1YmVkIFJlY2FsbDoiLCByZWNhbGwsICJcbiIpCgpgYGAKCiMjIENsdXN0cmluZzQKCiMjIyMgSy1tZWFucyBydW4gay1tZWFucyBjbHVzdGVyaW5nIHRvIGZpbmQgNSBjbHVzdGVycwoKYGBge3J9CiNzZXQgYSBzZWVkIGZvciByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24gIHRvIG1ha2UgdGhlIHJlc3VsdHMgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDg5NTMpCmttZWFucy5yZXN1bHQgPC0ga21lYW5zKGRhdGFfZm9yX2NsdXN0ZXIsNSkKIyBwcmludCB0aGUgY2x1c3Rlcm5nIHJlc3VsdAprbWVhbnMucmVzdWx0CmBgYAoKIyMjIHZpc3VhbGl6ZSBjbHVzdGVyaW5nCgpgYGB7cn0KIyB2aXN1YWxpemUgY2x1c3RlcmluZyAoNSBjbHVzdGVycykKaW5zdGFsbC5wYWNrYWdlcygiZmFjdG9leHRyYSIpCmxpYnJhcnkoZmFjdG9leHRyYSkKZnZpel9jbHVzdGVyKGttZWFucy5yZXN1bHQsIGRhdGEgPSBkYXRhX2Zvcl9jbHVzdGVyKQpgYGAKCiMjIyBoaWVyY3JjaGljYWwgY2x1c3RlcmluZwoKYGBge3J9CiMgZHJhdyBhIHNhbXBsZSBvZiA1MCByZWNvcmRzIGZyb20gdGhlIGRhdGEsIHNvIHRoYXQgdGhlIGNsdXN0ZXJpbmcgcGxvdCB3aWxsIG5vdCBiZSBvdmVyIGNyb3dkZWQgYW5kIGVhc3kgdG8gdW5kcmVzdGFuZCAKaWR4NDwtc2FtcGxlKDE6ZGltKGRhdGFfZm9yX2NsdXN0ZXIpWzFdLCA1MCkKc2FtcGxlX2M0PC1kYXRhX2Zvcl9jbHVzdGVyW2lkeDQsIF0KCiMjIGhpZXJjcmNoaWNhbGNsdXN0ZXJpbmcKaGM0LmN1dDwtIGhjdXQoc2FtcGxlX2M0LCBrID0gNSwgaGNfbWV0aG9kPSAiY29tcGxldGUiKQpgYGAKCiMjIyBkZW5kcm9ncmFtCgpkZW5kcm9ncmFtIGlzIGEgdHJlZSBkaWFncmFtIHRoYXQgZGlzcGxheXMgdGhlIGFycmFuZ2VtZW50IG9mIGRhdGEgcG9pbnRzIGluIGEgaGllcmFyY2hpY2FsIG9yZGVyIGJhc2VkIG9uIHRoZWlyIHNpbWlsYXJpdHkgb3IgZGlzc2ltaWxhcml0eS4KCmBgYHtyfQojIFZpc3VhbGl6ZSBkZW5kcm9ncmFtCmZ2aXpfZGVuZChoYzQuY3V0LHJlY3Q9IFRSVUUpCiMgVmlzdWFsaXplIGNsdXN0ZXIKZnZpel9jbHVzdGVyKGhjNC5jdXQsIGVsbGlwc2UudHlwZT0gImNvbnZleCIpCmBgYAoKIyMjICNhdmVyYWdlIHNpbGhvdWV0dGUKClRoaXMgbWV0aG9kIGNhbGN1bGF0ZXMgdGhlIGF2ZXJhZ2Ugc2lsaG91ZXR0ZSB3aWR0aCBmb3IgZGlmZmVyZW50IHZhbHVlcyBvZiBrLCBkZXRlcm1pbmluZyBob3cgd2VsbCBkYXRhIHBvaW50cyBmaXQgaW50byB0aGVpciBhc3NpZ25lZCBjbHVzdGVycy4gZGV0ZXJtaW5pbmcgaG93IHdlbGwgZGF0YSBwb2ludHMgZml0IGludG8gdGhlaXIgYXNzaWduZWQgY2x1c3RlcnMuCgpgYGB7cn0KICNhdmVyYWdlIHNpbGhvdWV0dGUgZm9yIGVhY2ggY2x1c3RlcnMgCmluc3RhbGwucGFja2FnZXMoY2x1c3RlcikKbGlicmFyeShjbHVzdGVyKQphdmdfc2lsIDwtIHNpbGhvdWV0dGUoa21lYW5zLnJlc3VsdCRjbHVzdGVyLGRpc3QoZGF0YV9mb3JfY2x1c3RlcikpICNhIGRpc3NpbWlsYXJpdHkgb2JqZWN0IGluaGVyaXRpbmcgZnJvbSBjbGFzcyBkaXN0IG9yIGNvZXJjaWJsZSB0byBvbmUuIElmIG5vdCBzcGVjaWZpZWQsIGRtYXRyaXggbXVzdCBiZS4KZnZpel9zaWxob3VldHRlKGF2Z19zaWwpI2stbWVhbnMgY2x1c3RlcmluZyB3aXRoIGVzdGltYXRpbmcgayBhbmQgaW5pdGlhbGl6YXRpb25zCmBgYAoKIyMjIEJDdWJlZCBwcmVjaXNpb24gYW5kIHJlY2FsbAoKQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsIGFyZSBtZXRyaWNzIHVzZWQgdG8gZXZhbHVhdGUgdGhlIHBlcmZvcm1hbmNlIG9mIGNsdXN0ZXJpbmcgYWxnb3JpdGhtcywgcGFydGljdWxhcmx5IGluIHRoZSBjb250ZXh0IG9mIGV2YWx1YXRpbmcgdGhlIHF1YWxpdHkgb2YgY2x1c3RlcmluZyBhc3NpZ25tZW50cyBmb3IgaW5kaXZpZHVhbCBkYXRhIHBvaW50cy4KCmBgYHtyfQoKY2x1c3Rlcl9hc3NpZ25tZW50cyA8LSBjKGttZWFucy5yZXN1bHQkY2x1c3RlcikKZ3JvdW5kX3RydXRoX2xhYmVscyA8LSBjKHdhdGVyX3BvdGFiaWxpdHkpCmRhdGEgPC0gZGF0YS5mcmFtZShjbHVzdGVyID0gY2x1c3Rlcl9hc3NpZ25tZW50cywgbGFiZWwgPSBncm91bmRfdHJ1dGhfbGFiZWxzKQoKIyBGdW5jdGlvbiB0byBjYWxjdWxhdGUgQkN1YmVkIHByZWNpc2lvbiBhbmQgcmVjYWxsCmNhbGN1bGF0ZV9iY3ViZWRfbWV0cmljcyA8LSBmdW5jdGlvbihkYXRhKSB7CiAgbiA8LSBucm93KGRhdGEpCiAgcHJlY2lzaW9uX3N1bSA8LSAwCiAgcmVjYWxsX3N1bSA8LSAwCgogIGZvciAoaSBpbiAxOm4pIHsKICAgIGNsdXN0ZXIgPC0gZGF0YSRjbHVzdGVyW2ldCiAgICBsYWJlbCA8LSBkYXRhJGxhYmVsW2ldCiAgICAKIyBDb3VudCB0aGUgbnVtYmVyIG9mIGl0ZW1zIGZyb20gdGhlIHNhbWUgY2F0ZWdvcnkgd2l0aGluIHRoZSBzYW1lIGNsdXN0ZXIKc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgPC0gc3VtKGRhdGEkbGFiZWxbZGF0YSRjbHVzdGVyID09IGNsdXN0ZXJdID09IGxhYmVsKQogICAgCiMgQ291bnQgdGhlIHRvdGFsIG51bWJlciBvZiBpdGVtcyBpbiB0aGUgc2FtZSBjbHVzdGVyCnRvdGFsX3NhbWVfY2x1c3RlciA8LSBzdW0oZGF0YSRjbHVzdGVyID09IGNsdXN0ZXIpCiAgICAKIyBDb3VudCB0aGUgdG90YWwgbnVtYmVyIG9mIGl0ZW1zIHdpdGggdGhlIHNhbWUgY2F0ZWdvcnkKdG90YWxfc2FtZV9jYXRlZ29yeSA8LSBzdW0oZGF0YSRsYWJlbCA9PSBsYWJlbCkKICAgIAojIENhbGN1bGF0ZSBwcmVjaXNpb24gYW5kIHJlY2FsbCBmb3IgdGhlIGN1cnJlbnQgaXRlbSBhbmQgYWRkIHRoZW0gdG8gdGhlIHN1bXMKcHJlY2lzaW9uX3N1bSA8LSBwcmVjaXNpb25fc3VtICsgc2FtZV9jYXRlZ29yeV9zYW1lX2NsdXN0ZXIgL3RvdGFsX3NhbWVfY2x1c3RlcgpyZWNhbGxfc3VtIDwtIHJlY2FsbF9zdW0gKyBzYW1lX2NhdGVnb3J5X3NhbWVfY2x1c3RlciAvIHRvdGFsX3NhbWVfY2F0ZWdvcnkKICB9CgogICMgQ2FsY3VsYXRlIGF2ZXJhZ2UgcHJlY2lzaW9uIGFuZCByZWNhbGwKICBwcmVjaXNpb24gPC0gcHJlY2lzaW9uX3N1bSAvIG4KICByZWNhbGwgPC0gcmVjYWxsX3N1bSAvIG4KCiAgcmV0dXJuKGxpc3QocHJlY2lzaW9uID0gcHJlY2lzaW9uLCByZWNhbGwgPSByZWNhbGwpKQp9CgojIENhbGN1bGF0ZSBCQ3ViZWQgcHJlY2lzaW9uIGFuZCByZWNhbGwKbWV0cmljcyA8LSBjYWxjdWxhdGVfYmN1YmVkX21ldHJpY3MoZGF0YSkKCiMgRXh0cmFjdCBwcmVjaXNpb24gYW5kIHJlY2FsbCBmcm9tIHRoZSBtZXRyaWNzCnByZWNpc2lvbiA8LSBtZXRyaWNzJHByZWNpc2lvbgpyZWNhbGwgPC0gbWV0cmljcyRyZWNhbGwKCiMgUHJpbnQgdGhlIHJlc3VsdHMKY2F0KCJCQ3ViZWQgUHJlY2lzaW9uOiIsIHByZWNpc2lvbiwgIlxuIikKY2F0KCJCQ3ViZWQgUmVjYWxsOiIsIHJlY2FsbCwgIlxuIikKCmBgYAoKIyMjIEVsYm93IG1ldGhvZAoKZWxib3cgbWV0aG9kIGhlbHBzIGZpbmQgdGhlIG9wdGltYWwgbnVtYmVyIG9mIGNsdXN0ZXJzIChrKSBpbiBrLW1lYW5zIGNsdXN0ZXJpbmcuIHRoZSAiZWxib3ciIHBvaW50IGlzIHdoZXJlIHRoZSByYXRlIG9mIGRlY3JlYXNlIGluIFdTUyBzbG93cywgaW5kaWNhdGluZyBhIGdvb2QgYmFsYW5jZSBiZXR3ZWVuIGNsdXN0ZXIgY291bnQgYW5kIGNsdXN0ZXIgY29tcGFjdG5lc3MuIFRoZSBnb2FsIGlzIHRvIHNlbGVjdCB0aGUgc21hbGxlc3QgayB0aGF0IHJldGFpbnMgbW9zdCBvZiB0aGUgZGF0YSdzIHZhcmlhYmlsaXR5LgoKYGBge3J9CiMgMy0gRWxib3cgbWV0aG9kCiNmdml6X25iY2x1c3QoKSB3aXRoIHdpdGhpbiBjbHVzdGVyIHN1bXMgb2Ygc3F1YXJlcyAod3NzKSBtZXRob2QKaW5zdGFsbC5wYWNrYWdlcyhmYWN0b2V4dHJhKQpsaWJyYXJ5KGZhY3RvZXh0cmEpIApmdml6X25iY2x1c3QoZGF0YV9mb3JfY2x1c3Rlciwga21lYW5zLCBtZXRob2QgPSAid3NzIikgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDQsIGxpbmV0eXBlID0gMikrCiAgbGFicyhzdWJ0aXRsZSA9ICJFbGJvdyBtZXRob2QiKQpgYGAKCiMjIyBUb3RhbCBXaXRoaW4tQ2x1c3RlciBTdW0gb2YgU3F1YXJlcyBmb3IgawoKV1NTIGlzIHRvIGdpdmUgeW91IGFuIGluZGljYXRpb24gb2YgaG93IHdlbGwgdGhlIGRhdGEgY2FuIGJlIHJlcHJlc2VudGVkIGJ5IGEgY2VydGFpbiBudW1iZXIgb2YgY2x1c3RlcnMuIEluIGstbWVhbnMgY2x1c3RlcmluZywgdHlwaWNhbGx5IGNob29zZSB0aGUgbnVtYmVyIG9mIGNsdXN0ZXJzIChrKSB0aGF0IG1pbmltaXplcyB0aGlzIHRvdGFsIFdTUy4KCmBgYHtyfQoKZm9yIChrIGluIDI6NSkgewogIGttZWFuc19yZXN1bHQgPC0ga21lYW5zKHdhdGVyX3BvdGFiaWxpdHksIGNlbnRlcnMgPSBrKQogIHRvdGFsX3dpdGhpbnNzIDwtIGttZWFuc19yZXN1bHQkdG90LndpdGhpbnNzCiAgY2F0KCJUb3RhbCBXaXRoaW4tQ2x1c3RlciBTdW0gb2YgU3F1YXJlcyBmb3IgayA9IiwgaywgIjoiLCB0b3RhbF93aXRoaW5zcywgIlxuIikKfQoKYGBgCgojIyMgQ29tcGFyaXNvbiBDcml0ZXJpYToKCnwgICAgICAgICAgICAgICAgICAgICAgICAgIHwgQ2x1c3RyaW5nMSB8IENsdXN0cmluZzIgIHwgQ2x1c3RyaW5nMyAgfCBDbHVzdHJpbmc0ICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS18CnwgYXZlcmFnZSBzaWxob3VldHRlIHdpZHRoIHwgMC4wOCAgICAgICB8IDAuMDggICAgICAgIHwgMC4wNyAgICAgICAgfCAwLjA4ICAgICAgICB8CnwgQkN1YmVkIFByZWNpc2lvbiAgICAgICAgIHwgMC4wMDUzNTA3ICB8IDAuMDA1NDE3MTMyIHwgMC4wMDU0NjY2NTYgfCAwLjAwNTUyNTI3OCB8CnwgQkN1YmVkIFJlY2FsbCAgICAgICAgICAgIHwgMC45NTAxMjA5ICB8IDAuOTMzNDc0MSAgIHwgMC45MjUwNzM2ICAgfCAwLjkyMDE1NjggICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICB8ICAgICAgICAgICAgIHwgICAgICAgICAgICAgfCAgICAgICAgICAgICB8CnwgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICB8ICAgICAgICAgICAgIHwgICAgICAgICAgICAgfCAgICAgICAgICAgICB8CgpUb3RhbCBXaXRoaW4tQ2x1c3RlciBTdW0gb2YgU3F1YXJlcyBmb3IgayA9IDIgOiAzNTQzNTczNjE3OAoKVG90YWwgV2l0aGluLUNsdXN0ZXIgU3VtIG9mIFNxdWFyZXMgZm9yIGsgPSAzIDogMTgwMDU2MzYyMDcKClRvdGFsIFdpdGhpbi1DbHVzdGVyIFN1bSBvZiBTcXVhcmVzIGZvciBrID0gNCA6IDEwNjQ0Njg2OTEzCgpUb3RhbCBXaXRoaW4tQ2x1c3RlciBTdW0gb2YgU3F1YXJlcyBmb3IgayA9IDUgOiA3MjYzMTUwODc2Cg==